home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 6 / QRZ Ham Radio Callsign Database - Volume 6.iso / pc / files / dsp / dspkgctr.z / dspkgctr / gcc / config / dsp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-08  |  65.4 KB  |  2,790 lines

  1. /* subroutines and data common to all motorola dsp gcc retargets. 
  2.    copyright (C) 1991 Motorola, Inc.
  3.  
  4.    $Id: dsp.c,v 1.20 92/04/06 11:26:08 jeff Exp $
  5. */
  6.  
  7. /* forward declarations */
  8. #if defined ( _MSDOS )
  9. void warning ( char * s, ... );
  10. #endif
  11.  
  12. /* run time and load time counter setups. */
  13.  
  14. char *x_load_default = NULL, *x_run_default = "x:";
  15. char *x_load = NULL, *x_run = "x:";
  16. char *y_load_default = NULL, *y_run_default = "y:"; 
  17. char *y_load = NULL, *y_run = "y:";
  18. char *l_load_default = NULL, *l_run_default = "l:"; 
  19. char *l_load = NULL, *l_run = "l:";
  20. char *p_load_default = NULL, *p_run_default = "p:"; 
  21. char *p_load = NULL, *p_run = "p:";
  22.  
  23. #if defined( _INTELC32_ )
  24. #include "bblock.h"
  25. #else
  26. #include "basic-block.h"
  27. #endif
  28.  
  29. /* reload pass cleanup.
  30.  
  31.    The gcc register allocation scheme, as it exists in 1.37.1 leaves much
  32.    to be desired. The reload section in particular, creates excessive and
  33.    unnecessary loads and stores, because it does not take (the lack of) 
  34.    global variable interference into account. 
  35.  
  36.    Until the register allocation phase ( local-alloc.c, global-alloc.c, 
  37.    reload.c, and reload1.c ) is replaced, we will bolt on this post allocation
  38.    "reload cleaner". It will scrub each basic block as well as can be done 
  39.    without considering global data flow information.
  40.  
  41.    The Algorithm is as follows:
  42.  
  43.    foreach basic block b in the function,
  44.  
  45.      compress_lives ( b )
  46.      kill_loads ( b )
  47.      kill_stores ( b )
  48.  
  49.    end
  50.  
  51.    ; compress_lives - if a reload can be averted by moving a register
  52.    ; transfer, do so and let kill_loads/stores eliminate the reload.
  53.  
  54.    ; kill_loads - attempt to eliminate or alter gratuitous reload created 
  55.    ; load instructions. try to eliminate loads by getting the value from 
  56.    ; a source cheaper than a stack slot.
  57.  
  58.    ; kill_stores - attempt to eliminate gratuitous reload created store 
  59.    ; instructions.
  60.  
  61. */
  62.  
  63. static int safe_strcmp ( );
  64. static void compliv_mark_touched ( );
  65. static void compress_lives ( );
  66. static int get_offset ( );
  67. static void global_kill_stores ( );
  68. static void kill_loads ( );
  69. static void kill_stores ( );
  70. static void kill_prior_contents ( );
  71. static void kloads_mark_touched ( );
  72. static void kstores_mark_touched ( );
  73. static int modes_compatable_p ( );
  74. static int reg_possibly_live ( );
  75. static int reg_possibly_live_between_p ( );
  76. static int rtx_same_p ( );
  77. static int trailing_affected_slots ( );
  78.  
  79. /**************************************************************************/
  80. /* this is the main routine for cleaning up after the reload pass is run. */
  81. /* is is called by toplev.c.                                              */
  82. /**************************************************************************/
  83.  
  84. void
  85. cleanup_reloads ( insns )
  86.     rtx insns;
  87. {
  88.     int block_num = n_basic_blocks;
  89.     
  90.     while ( block_num -- )
  91.     {
  92.     compress_lives ( block_num );
  93.     kill_loads ( block_num );
  94.     kill_stores ( block_num );
  95.     }
  96.     global_kill_stores ( insns );
  97. }
  98.  
  99. /* contains the last value loaded into a register. used by kill_loads. */
  100. static rtx reg_value[ FIRST_PSEUDO_REGISTER ];
  101.     
  102. /* the mode associated with the value in a register. used by kill_loads. */
  103. static enum machine_mode reg_value_mode[ FIRST_PSEUDO_REGISTER ];
  104.     
  105. /* contains the last value loaded into a stack slot. the array is 
  106.    allocated by either kill_loads or compress_lives. compress_lives uses
  107.    slot_value as a mapping from slot offsets to the last insn to set that
  108.    slot. */
  109. static rtx *slot_value;
  110.  
  111. /* the mode associated with the value in a stack slot. the memory for
  112.    the array is allocated by kill_loads or compress_lives. */
  113. static enum machine_mode *slot_value_mode;
  114.     
  115. /* a marker for subsequent memory (or register) locations affected
  116.    by a wider than single unit move. */
  117. rtx look_to_previous_elem;
  118.  
  119. static void
  120. kill_loads ( block_num )
  121.     int block_num;
  122. {
  123.     extern int get_frame_size ( );
  124.     
  125.     /* the maximum stack slot offset in this function. */
  126.     int max_slot_offset = get_frame_size ( ) + 1
  127.     
  128. #ifdef FRAME_GROWS_DOWNWARD
  129.     - STARTING_FRAME_OFFSET;
  130. #else
  131.     + STARTING_FRAME_OFFSET;
  132. #endif
  133.  
  134.     /* this is the generic last location used, which may be aliased but
  135.        not volatile. it allows us to eliminate senseless loads from one
  136.        non-reload generated address. */
  137.     rtx non_reload_address = NULL;
  138.     
  139.     /* this is the value associated with that address. */
  140.     rtx nra_value;
  141.     
  142.     /* this is the mode associated with that value. */
  143.     enum machine_mode nra_mode;
  144.     
  145.     /* allocate memory for the grouping marker. */
  146.     look_to_previous_elem = (rtx) alloca ( sizeof ( struct rtx_def ));
  147.     
  148.     /* allocate memory for the slot_value and mode arrays. */
  149.     slot_value = (rtx*) alloca ( sizeof ( rtx ) * max_slot_offset );
  150.     slot_value_mode = (enum machine_mode*) 
  151.     alloca ( sizeof ( enum machine_mode ) * max_slot_offset );
  152.  
  153.     /*******************************/
  154.     /* initialize data structures. */
  155.     /*******************************/
  156.     { 
  157.     /* in_defs are the unknown values resident in storage locations upon
  158.        entry to the basic block. */
  159.  
  160.     rtx in_defs = (rtx) 
  161.         alloca (( max_slot_offset + FIRST_PSEUDO_REGISTER ) * 
  162.             sizeof ( struct rtx_def ));
  163.  
  164.     int i = max_slot_offset;
  165.     
  166.     while ( i -- )
  167.     {
  168.         /* each slot location has a unique unknown value upon block 
  169.            entry. */
  170.          PUT_CODE ( in_defs, UNKNOWN );
  171.         slot_value[i] = in_defs ++;
  172.         slot_value_mode[i] = VOIDmode;
  173.     }
  174.     
  175.     i = FIRST_PSEUDO_REGISTER;
  176.     
  177.     while ( i -- )
  178.     {
  179.         PUT_CODE ( in_defs, UNKNOWN );
  180.         reg_value[i] = in_defs ++;
  181.         reg_value_mode[i] = VOIDmode;
  182.     }
  183.     }
  184.     
  185.     /* scan through the basic block once, in execution order. */
  186.     { 
  187.     rtx insn = basic_block_head[ block_num ];
  188.     rtx tail = basic_block_end[ block_num ];
  189.     
  190.     while ( insn != tail )
  191.     {
  192.         rtx body;
  193.         
  194.         if ( CALL_INSN == GET_CODE ( insn ))
  195.         {
  196.         /* for a call, make sure that all of the call clobbered
  197.            registers are marked as undefined. */
  198.         
  199.         int i = FIRST_PSEUDO_REGISTER;
  200.         
  201.         while ( i -- )
  202.         {
  203.             if (( TEST_HARD_REG_BIT ( call_used_reg_set, i )) ||
  204.             ( TEST_HARD_REG_BIT ( fixed_reg_set, i )))
  205.             {
  206.             reg_value[i] = rtx_alloc ( UNKNOWN );
  207.             reg_value_mode[i] = VOIDmode;
  208.             }
  209.         }
  210.         insn = NEXT_INSN ( insn );
  211.         
  212.         continue;
  213.         }
  214.         
  215.         if ( INSN != GET_CODE ( insn ))
  216.         {
  217.         insn = NEXT_INSN ( insn );
  218.  
  219.         continue;
  220.         }
  221.         
  222.         body = PATTERN ( insn );
  223.  
  224.         /******************************************/
  225.         /* is this a register load of some kind ? */
  226.         /******************************************/
  227.  
  228.         if (( SET == GET_CODE ( body )) &&
  229.         (( REG == GET_CODE ( SET_DEST ( body ))) ||
  230.          (( SUBREG == GET_CODE ( SET_DEST ( body ))) &&
  231.           ( REG == GET_CODE ( XEXP ( SET_DEST ( body ), 0 ))))))
  232.         {
  233.         enum rtx_code src_code = GET_CODE ( SET_SRC ( body ));
  234.         
  235.         rtx set_dest = (( REG == GET_CODE ( SET_DEST ( body ))) ?
  236.                 SET_DEST ( body ) :
  237.                 XEXP ( SET_DEST ( body ), 0 ));
  238.  
  239.         int regno = REGNO ( set_dest );
  240.         
  241.         /* if the register being set is part of the address being
  242.            tracked as the "non_reload_address", then that address
  243.            must be invalidated. */
  244.  
  245.         if ( reg_mentioned_p ( set_dest, non_reload_address ))
  246.         {
  247.             non_reload_address = NULL;
  248.             nra_value = NULL;
  249.         }
  250.         
  251.         /***************************************************/
  252.         /* is the register being set to a constant value ? */
  253.         /***************************************************/
  254.  
  255.         if (( CONST_INT == src_code ) ||
  256.             ( CONST_DOUBLE == src_code ) ||
  257.             ( CONST == src_code ))
  258.         {
  259.             /* does the register already have this value ? */
  260.  
  261.             if ( rtx_same_p ( reg_value[ regno ], SET_SRC ( body )) &&
  262.             modes_compatable_p ( reg_value_mode[ regno ],
  263.                         GET_MODE ( SET_DEST ( body ))))
  264.             {
  265.             /* yes, eliminate a needless constant load. */
  266.  
  267.             PUT_CODE ( insn, NOTE );
  268.             NOTE_LINE_NUMBER ( insn ) = NOTE_INSN_DELETED;
  269.             NOTE_SOURCE_FILE ( insn ) = 0;
  270.             }
  271.             else
  272.             {
  273.             /* note the new register contents. */
  274.  
  275.             kill_prior_contents ( reg_value, regno );
  276.                 
  277.             reg_value[ regno ] = SET_SRC ( body );
  278.             reg_value_mode[ regno ] = 
  279.                 GET_MODE ( SET_DEST ( body ));
  280.  
  281.             /* note any subsequent registers clobbered by
  282.                the load. */
  283.             {
  284.                 int i = HARD_REGNO_NREGS ( regno, 
  285.                               reg_value_mode[ regno ]);
  286.                 
  287.                 while ( -- i )
  288.                 {
  289.                 reg_value[ regno + i ] = look_to_previous_elem;
  290.                 }
  291.             }
  292.             }
  293.         }
  294.         
  295.         /*****************************************/
  296.         /* is this a register to register copy ? */
  297.         /*****************************************/
  298.  
  299.         else if (( REG == src_code ) ||
  300.              (( SUBREG == src_code ) &&
  301.               ( REG == GET_CODE ( XEXP ( SET_SRC ( body ), 0 )))))
  302.         {
  303.             int src_regno = (( REG == src_code ) ?
  304.                      REGNO ( SET_SRC ( body )) :
  305.                      REGNO ( XEXP ( SET_SRC ( body ), 0 )));
  306.             
  307.             /* if the register already has this value, then ... */
  308.  
  309.             if ( rtx_same_p ( reg_value[ src_regno ],
  310.                      reg_value[ regno ]) &&
  311.             modes_compatable_p ( reg_value_mode[ regno ],
  312.                         GET_MODE ( SET_DEST ( body ))))
  313.             {
  314.  
  315.             /* ... eliminate a needless register copy. */
  316.  
  317.             PUT_CODE ( insn, NOTE );
  318.             NOTE_LINE_NUMBER ( insn ) = NOTE_INSN_DELETED;
  319.             NOTE_SOURCE_FILE ( insn ) = 0;
  320.  
  321.             /* note any slight change in mode. */
  322.             
  323.             reg_value_mode[ regno ] = 
  324.                 GET_MODE ( SET_DEST ( body ));
  325.             }
  326.             else
  327.             {
  328.             /* take note of the new value. */
  329.  
  330.             kill_prior_contents ( reg_value, regno );
  331.             
  332.             reg_value[ regno ] = reg_value[ src_regno ];
  333.             reg_value_mode[ regno ] = GET_MODE ( SET_DEST ( body));
  334.             
  335.             /* note any subsequently affected regs. */
  336.                 {
  337.                 int i = HARD_REGNO_NREGS ( regno,
  338.                               reg_value_mode[ regno ]);
  339.                 
  340.                 while ( -- i )
  341.                 {
  342.                 reg_value[ regno + i ] = look_to_previous_elem;
  343.                 }
  344.             }
  345.             }
  346.         }
  347.         
  348.         /***************************************/
  349.         /* is this a memory to register load ? */
  350.         /***************************************/
  351.  
  352.         else if (( MEM == src_code ) ||
  353.              (( SUBREG == src_code ) &&
  354.               ( MEM == GET_CODE ( XEXP ( SET_SRC ( body ), 0 )))))
  355.         {
  356.             /*********************************************************/
  357.             /* is this a reload generated load from the stack ?      */
  358.             /* do we know what value resides in this stack slot ?    */
  359.             /* do we already have it in this register, or can we get */
  360.             /* it cheaper from somewhere else ?                      */
  361.             /*********************************************************/
  362.  
  363.             if (( MEM == src_code ) ?
  364.             RTX_RELOAD_GENERATED_P ( XEXP ( SET_SRC ( body ),0 )) :
  365.             RTX_RELOAD_GENERATED_P ( XEXP ( XEXP ( 
  366.                           SET_SRC ( body ), 0 ), 0 )))
  367.             { 
  368.             int offset = 
  369.                 (( MEM == src_code ) ?
  370.                  get_offset ( SET_SRC ( body )) :
  371.                  get_offset ( XEXP ( SET_SRC ( body ), 0 )));
  372.             
  373.             if ( rtx_same_p ( reg_value[ regno ],
  374.                      slot_value[ offset ]) &&
  375.                 modes_compatable_p ( slot_value_mode[ offset ],
  376.                         reg_value_mode[ regno ] ) &&
  377.                 modes_compatable_p ( slot_value_mode[ offset ],
  378.                         GET_MODE ( SET_DEST ( body ))))
  379.             {
  380.                 /* eliminate needless register load. */
  381.  
  382.                 PUT_CODE ( insn, NOTE );
  383.                 NOTE_LINE_NUMBER ( insn ) = NOTE_INSN_DELETED;
  384.                 NOTE_SOURCE_FILE ( insn ) = 0;
  385.             }
  386.             else
  387.             {
  388.                 /* take note of the new value. */
  389.  
  390.                 kill_prior_contents ( reg_value, regno );
  391.                 
  392.                 reg_value[ regno ] = slot_value[ offset ];
  393.                 reg_value_mode[ regno ] = 
  394.                 GET_MODE ( SET_DEST ( body ));
  395.  
  396.                 /* note any subsequently affected regs. */
  397.                 {
  398.                 int i = HARD_REGNO_NREGS ( regno,
  399.                           reg_value_mode[ regno ]);
  400.                 
  401.                 while ( -- i )
  402.                 {
  403.                     reg_value[ regno + i ] = 
  404.                     look_to_previous_elem;
  405.                 }
  406.                 }
  407.                 
  408.                 /* can we get that value cheaper ? i.e from
  409.                    a constant load or another register ? */
  410.  
  411.                 { 
  412.                 /* a register transfer would be the cheapest
  413.                    way, otherwise take a constant load if 
  414.                    possible. */
  415.  
  416.                 rtx orig_src = SET_SRC ( body );
  417.                 rtx reg_val = reg_value[ regno ];
  418.                 
  419.                 int other_regno = FIRST_PSEUDO_REGISTER;
  420.                 
  421.                 while ( other_regno -- )
  422.                 {
  423.                     if (( regno != other_regno ) &&
  424.                     rtx_same_p ( reg_val,
  425.                             reg_value[ other_regno ])
  426.                     && ( reg_value_mode[ regno ] ==
  427.                         reg_value_mode[ other_regno ]))
  428.                     {
  429.                     SET_SRC ( body ) = 
  430.                         gen_rtx ( REG, 
  431.                              reg_value_mode[ regno ],
  432.                              other_regno );
  433.                     
  434.                     /* this may mean that we need to
  435.                        "re-recog" this insn. */
  436.                     
  437.                     INSN_CODE ( insn ) = -1;
  438.                     
  439.                     /* a NULL reg_val means that we found
  440.                        a suitable register source. */
  441.  
  442.                     reg_val = NULL;
  443.                     
  444.                     break;
  445.                     }
  446.                 }
  447.                 
  448.                 /* we didn't get a register, try for a
  449.                    constant load. */
  450.  
  451.                 if (( NULL != reg_val ) &&
  452.                     ( orig_src == SET_SRC ( body )) &&
  453.                     (( CONSTANT_P ( reg_val )) ||
  454.                      ( CONST_DOUBLE == GET_CODE ( reg_val )))
  455.                     &&
  456.                     modes_compatable_p ( GET_MODE ( reg_val ),
  457.                     GET_MODE ( SET_DEST ( body ))))
  458.                 {
  459.                     SET_SRC ( body ) = reg_val;
  460.                     
  461.                     /* this may mean that we need to
  462.                        "re-recog" this insn. */
  463.                     
  464.                     INSN_CODE ( insn ) = -1;
  465.                 }
  466.                 }
  467.             }
  468.             }
  469.             
  470.             /*****************************************************/
  471.             /* otherwise is this a load from the last non-reload */
  472.             /* address stored to ? (remember we track only one   */
  473.             /* potentially aliased location at a time.           */
  474.             /*****************************************************/
  475.  
  476.             else if (( MEM == src_code ) ?
  477.                  rtx_same_p ( non_reload_address,
  478.                      XEXP ( SET_SRC ( body ), 0 )) :
  479.                  rtx_same_p ( non_reload_address,
  480.                      XEXP ( XEXP ( SET_SRC ( body ),0),0)))
  481.             {
  482.             /* is the same value resident in this register 
  483.                already ? */
  484.  
  485.             if (( MEM == src_code ) ?
  486.                 MEM_VOLATILE_P ( SET_SRC ( body )) :
  487.                 MEM_VOLATILE_P ( XEXP ( SET_SRC ( body ), 0 )))
  488.             {
  489.                 non_reload_address = NULL;
  490.             }
  491.             else if ( rtx_same_p ( nra_value, reg_value[ regno ]) 
  492.                  && nra_mode == reg_value_mode[ regno ])
  493.             {
  494.                 /* the value is already here. kill the needless
  495.  
  496.                    load instruction. */
  497.                 PUT_CODE ( insn, NOTE );
  498.                 NOTE_LINE_NUMBER ( insn ) = NOTE_INSN_DELETED;
  499.                 NOTE_SOURCE_FILE ( insn ) = 0;
  500.             }
  501.             else /* note that we performed the load. */
  502.             {
  503.                 kill_prior_contents ( reg_value, regno );
  504.  
  505.                 reg_value[ regno ] = nra_value;
  506.                 reg_value_mode[ regno ] =
  507.                 GET_MODE ( SET_DEST ( body ));
  508.  
  509.                 /* note any subsequently affected regs. */
  510.                 {
  511.                 int i = HARD_REGNO_NREGS ( regno,
  512.                           reg_value_mode[ regno ]);
  513.                 
  514.                 while ( -- i )
  515.                 {
  516.                     reg_value[ regno + i ] = 
  517.                     look_to_previous_elem;
  518.                 }
  519.                 }
  520.             }
  521.             }
  522.             
  523.             /****************************************************/
  524.             /* it's a load from a non-reload generated mem src. */
  525.             /****************************************************/
  526.  
  527.             else 
  528.             {
  529.             enum machine_mode dest_mode = 
  530.                 GET_MODE ( SET_DEST ( body ));
  531.  
  532.             int i = HARD_REGNO_NREGS ( regno, dest_mode );
  533.  
  534.             kill_prior_contents ( reg_value, regno );
  535.             
  536.             reg_value[ regno ] = rtx_alloc ( UNKNOWN );
  537.             reg_value_mode[ regno ] = dest_mode;
  538.  
  539.             while ( -- i )
  540.             {
  541.                 reg_value[ regno + i ] = look_to_previous_elem;
  542.             }
  543.             }
  544.         }
  545.  
  546.         /*******************************************************/
  547.         /* the register must be getting set by some sort of    */
  548.         /* arithmetic op. create a new undefined value for it. */
  549.         /*******************************************************/
  550.  
  551.         else
  552.         {
  553.             /* mark the register value as completely undefined. */
  554.  
  555.             reg_value[ regno ] = rtx_alloc ( UNKNOWN );
  556.             reg_value_mode[ regno ] = GET_MODE ( SET_DEST ( body ));
  557.             
  558.             { 
  559.             int i = HARD_REGNO_NREGS ( regno,
  560.                           reg_value_mode[ regno ]);
  561.             
  562.             while ( -- i )
  563.             {
  564.                 reg_value[ i + regno ] = look_to_previous_elem;
  565.             }
  566.             }
  567.         }
  568.         }
  569.         
  570.         /****************************************************************/
  571.         /* for stack slot stores:                                       */
  572.         /* if the source is a register, then copy the source register's */
  573.         /* value as the new stack slot's value.                         */
  574.         /* otherwise, mark the stack slot as undefined with a           */
  575.         /* a new UNKNOWN.                                               */
  576.         /****************************************************************/
  577.  
  578.         else if (( SET == GET_CODE ( body )) &&
  579.              ((( MEM == GET_CODE ( SET_DEST ( body ))) &&
  580.                ( RTX_RELOAD_GENERATED_P ( XEXP ( SET_DEST ( body ),
  581.                             0 )))) ||
  582.               (( SUBREG == GET_CODE ( SET_DEST ( body ))) &&
  583.                ( MEM == GET_CODE ( XEXP ( SET_DEST ( body ), 0 ))) &&
  584.                ( RTX_RELOAD_GENERATED_P ( XEXP ( 
  585.                     XEXP ( SET_DEST ( body ), 0 ), 0 ))))))
  586.         {
  587.         int offset = (( MEM == GET_CODE ( SET_DEST ( body ))) ?
  588.                   get_offset ( SET_DEST ( body )) :
  589.                   get_offset ( XEXP ( SET_DEST ( body ), 0 )));
  590.  
  591.         if ( REG == GET_CODE ( SET_SRC ( body )))
  592.         {
  593.             int regno = REGNO ( SET_SRC ( body ));
  594.             
  595.             kill_prior_contents ( slot_value, offset );
  596.             
  597.             slot_value[ offset ] = reg_value[ regno ];
  598.             slot_value_mode[ offset ] = GET_MODE ( SET_DEST ( body ));
  599.             
  600.             /* handle the case where more than one stack slot 
  601.                location is affected by the store. */
  602.             { 
  603.             int i =
  604.               trailing_affected_slots ( slot_value_mode[ offset ]);
  605.             
  606.             while ( i )
  607.             {
  608.                 slot_value[ offset + ( i -- )] = 
  609.                 look_to_previous_elem;
  610.             }
  611.             }
  612.         }
  613.         else /* slot value is considered unknown. */
  614.         {
  615.             kill_prior_contents ( slot_value, offset );
  616.             
  617.             slot_value[ offset ] = rtx_alloc ( UNKNOWN );
  618.             slot_value_mode[ offset ] = GET_MODE ( SET_DEST ( body ));
  619.             
  620.             /* handle the case where more than one stack slot 
  621.                location is affected by the store. */
  622.             { 
  623.             int i =
  624.             trailing_affected_slots ( GET_MODE ( SET_DEST ( body )));
  625.             
  626.             while ( i )
  627.             {
  628.                 slot_value[ offset + ( i -- )] = 
  629.                 look_to_previous_elem;
  630.             }
  631.             }
  632.         }
  633.         }
  634.  
  635.         /**************************************************************/
  636.         /* otherwise if we have a non-volatile memory store, we track */
  637.         /* the value and the address until another store of this type */
  638.         /* is found, or until an instruction with non-obvious         */
  639.         /* side-effects is encountered.                               */
  640.         /**************************************************************/
  641.  
  642.         else if (( SET == GET_CODE ( body )) &&
  643.              ( REG == GET_CODE ( SET_SRC ( body ))) &&
  644.              ((( MEM == GET_CODE ( SET_DEST ( body ))) &&
  645.                ( ! MEM_VOLATILE_P ( SET_DEST ( body )))) ||
  646.               (( SUBREG == GET_CODE ( SET_DEST ( body ))) &&
  647.                ( MEM == GET_CODE ( XEXP ( SET_DEST ( body ), 0 ))) &&
  648.                ( ! MEM_VOLATILE_P ( XEXP ( SET_DEST ( body ), 0 ))))))
  649.         {
  650.         non_reload_address = ( MEM == GET_CODE ( SET_DEST ( body ))) ?
  651.             XEXP ( SET_DEST ( body ), 0 ) :
  652.             XEXP ( XEXP ( SET_DEST ( body ), 0 ), 0 );
  653.         
  654.         nra_value = reg_value[ REGNO ( SET_SRC ( body )) ];
  655.         nra_mode = GET_MODE ( SET_DEST ( body ));
  656.         }
  657.  
  658.         /**********************************************************/
  659.         /* for others, note affected registers and stack slots as */
  660.         /* undefined.                                             */
  661.         /**********************************************************/
  662.  
  663.         else
  664.         {
  665.         kloads_mark_touched ( body );
  666.  
  667.         /* also, we might have boottied the memory location pointed
  668.            to by the non-reload address. to be conservative, we
  669.            must nix its value. */
  670.  
  671.         non_reload_address = NULL;
  672.         nra_value = NULL;
  673.         }
  674.         insn = NEXT_INSN ( insn );
  675.     }
  676.     }
  677. #if defined( USE_C_ALLOCA )
  678.     (void) alloca ( 0 );
  679. #endif
  680. }
  681.  
  682. /* an array of chars, one char corresponding to each stack slot. a 'u'
  683.    means that the associated stack slot has been used since the last
  684.    def, in a bottom up traversal of the basic block. a 'd' meas that
  685.    the last reference to the slot was a def. back to back defs indicate
  686.    that the earlier def (in the order of execution) is useless. 
  687.  
  688.    storage space for the array is allocated by kill_stores. */
  689.  
  690. static char *slot_ref;
  691.  
  692. static void
  693. kill_stores ( block_num )
  694.     int block_num;
  695. {
  696.     extern int get_frame_size ( );
  697.     
  698.     /* the maximum stack slot offset in this function. */
  699.     int max_slot_offset = get_frame_size ( ) + 1
  700. #ifdef FRAME_GROWS_DOWNWARD
  701.     - STARTING_FRAME_OFFSET;
  702. #else
  703.     + STARTING_FRAME_OFFSET;
  704. #endif
  705.  
  706.     /* allocate storage for slot_ref array */
  707.     slot_ref = (char*) alloca ( sizeof ( char ) * max_slot_offset );
  708.  
  709.     /* initialize slots to all 'u', anticipating potential use refs beyond the
  710.        end of the basic block. */
  711.     {
  712.     int i = max_slot_offset;
  713.     
  714.     while ( i -- )
  715.     {
  716.         slot_ref[i] = 'u';
  717.     }
  718.     }
  719.     
  720.     /* traverse the block in bottom up fashion, removing useless defs of
  721.        reload generated stack slots. */
  722.     {
  723.     rtx head = basic_block_head[ block_num ];
  724.     rtx insn = basic_block_end[ block_num ];
  725.  
  726.     while ( insn != head )
  727.     {
  728.         if ( INSN == GET_CODE ( insn ))
  729.         {
  730.         rtx body = PATTERN ( insn );
  731.         
  732.         /* do we have a store to a stack slot ? */
  733.         
  734.         if (( SET == GET_CODE ( body )) &&
  735.             ((( MEM == GET_CODE ( SET_DEST ( body ))) &&
  736.               ( RTX_RELOAD_GENERATED_P ( XEXP ( SET_DEST ( body ), 
  737.                               0 )))) ||
  738.              (( SUBREG == GET_CODE ( SET_DEST ( body ))) &&
  739.               ( MEM == GET_CODE ( XEXP ( SET_DEST ( body ), 0 ))) &&
  740.               ( RTX_RELOAD_GENERATED_P ( XEXP ( XEXP ( SET_DEST (
  741.                                      body )
  742.                                   , 0 ), 0 ))))))
  743.         {
  744.             int offset = ( MEM == GET_CODE ( SET_DEST ( body ))) ?
  745.             get_offset ( SET_DEST ( body )) :
  746.                 get_offset ( XEXP ( SET_DEST ( body ), 0 ));
  747.             
  748.             if ( 'd' == slot_ref[ offset ] )
  749.             {
  750.             /* a def followed by a def. this is the criteria for
  751.                a 'useless' def. eliminate this def. */
  752.             
  753.             PUT_CODE ( insn, NOTE );
  754.             NOTE_LINE_NUMBER ( insn ) = NOTE_INSN_DELETED;
  755.             NOTE_SOURCE_FILE ( insn ) = 0;
  756.             }
  757.             else /* 'u' */
  758.             {
  759.             /* make the slot as defined, and continue. */
  760.             
  761.             slot_ref[ offset ] = 'd';
  762.             }
  763.         }
  764.         else
  765.         {
  766.             /* note any stack slot uses within the insn. */
  767.             
  768.             kstores_mark_touched ( body );
  769.         }
  770.         }
  771.         insn = PREV_INSN ( insn );
  772.     }
  773.     }
  774. #if defined( USE_C_ALLOCA )
  775.     (void) alloca ( 0 );
  776. #endif
  777. }
  778.  
  779. static int
  780. modes_compatable_p ( m1, m2 )
  781.     enum machine_mode m1, m2;
  782. {
  783.     if (( VOIDmode == m1 || VOIDmode == m2 || m1 == m2 ) ||
  784. #if defined( DSP56000 )
  785.     (( SImode == m1 || QImode == m1 || PSImode == m1 ) &&
  786.      ( SImode == m2 || QImode == m2 || PSImode == m2 )))
  787. #elif defined( DSP96000 )
  788.     (( DImode == m1 || SImode == m1 || QImode == m1 || PSImode == m1 ) &&
  789.      ( DImode == m2 || SImode == m2 || QImode == m2 || PSImode == m2 )))
  790. #endif
  791.     {
  792.     return 1;
  793.     }
  794.     return 0;
  795. }
  796.  
  797. /* get the integer frame pointer offset of a reload created stack slot. */
  798.  
  799. static int
  800. get_offset ( mem )
  801.     rtx mem;
  802. {
  803.     rtx addr;
  804.     
  805.     while ( SUBREG == GET_CODE ( mem ))
  806.     {
  807.     mem = XEXP ( mem, 0 );
  808.     }
  809.     addr = XEXP ( mem, 0 );
  810.     
  811.     if ( CONST_INT == GET_CODE ( addr ))
  812.     {
  813.     return INTVAL ( addr );
  814.     }
  815.     else if ( PLUS == GET_CODE ( addr ))
  816.     {
  817.     if ( CONST_INT == GET_CODE ( XEXP ( addr, 0 )))
  818.     {
  819.         return INTVAL ( XEXP ( addr,  0 ));
  820.     }
  821.     else if ( CONST_INT == GET_CODE ( XEXP ( addr, 1 )))
  822.     {
  823.         return INTVAL ( XEXP ( addr,  1 ));
  824.     }
  825.     else
  826.     {
  827.         abort ( );
  828.     }
  829.     }
  830.     else
  831.     {
  832.     abort ( );
  833.     }
  834. }
  835.  
  836. /* indicate whether, and how many, subsequent stack slots will be affected
  837.    by a memory write with the given mode. */
  838.  
  839. static int
  840. trailing_affected_slots ( mode )
  841.     enum machine_mode mode;
  842. {
  843.     if ( 'l' == memory_model )
  844.     {
  845.     return 0;
  846.     }
  847.     else
  848.     {
  849. #if defined( DSP56000 )
  850.     if (( DImode == mode ) || ( SFmode == mode ) || ( DFmode == mode ))
  851.     {
  852.         return 1;
  853.     }
  854. #endif
  855. #if defined( DSP96000 )
  856.     if (( DImode == mode ) || ( DFmode == mode ))
  857.     {
  858.         return 1;
  859.     }
  860. #endif
  861.     return 0;
  862.     }
  863. }
  864.  
  865. /* do a and b imply the same value ? we have to check for UNKNOWNs, as 
  866.    rtx_equal_p will abort on them. */
  867.  
  868. static int
  869. rtx_same_p ( a, b )
  870.     rtx a, b;
  871. {
  872.     if (( NULL == a ) ||
  873.     ( NULL == b ))
  874.     {
  875.     return 0;
  876.     }
  877.     
  878.     if ( a == b )
  879.     {
  880.     return 1;
  881.     }
  882.  
  883.     if (( UNKNOWN == GET_CODE ( a )) ||
  884.     ( UNKNOWN == GET_CODE ( b )))
  885.     {
  886.     return 0;
  887.     }
  888.     
  889.     return rtx_equal_p ( a, b );
  890. }
  891.  
  892. static void
  893. kstores_mark_touched ( body )
  894.     rtx body;
  895. {
  896.     if ( SET == GET_CODE ( body ))
  897.     {
  898.     body = SET_SRC ( body );
  899.  
  900.     if ((( MEM == GET_CODE ( body )) &&
  901.          ( RTX_RELOAD_GENERATED_P ( XEXP ( body, 0 )))) ||
  902.         (( SUBREG == GET_CODE ( body )) &&
  903.          ( MEM == GET_CODE ( XEXP ( body, 0 ))) &&
  904.          ( RTX_RELOAD_GENERATED_P ( XEXP ( XEXP ( body, 0 ), 0 )))))
  905.     {
  906.         int offset = ( MEM == GET_CODE ( body )) ?
  907.         get_offset ( body ) : get_offset ( XEXP ( body, 0 ));
  908.  
  909.         slot_ref[ offset ] = 'u';
  910.         
  911.         /* note subsequent slots affected. */
  912.         { 
  913.         int i = trailing_affected_slots ( GET_MODE ( body ));
  914.         
  915.         while ( i )
  916.         {
  917.             slot_ref[ ( i -- ) + offset ] = 'u';
  918.         }
  919.         }
  920.     }
  921.     }
  922.     else
  923.     { 
  924.     char *fmt = GET_RTX_FORMAT ( GET_CODE ( body ));
  925.     char c, *p = fmt;
  926.     
  927.     while ( '\0' != ( c = *p ))
  928.     {
  929.         switch ( c )
  930.         {
  931.         case 'e':
  932.         kstores_mark_touched ( XEXP ( body, p - fmt ));
  933.         break;
  934.         
  935.         case 'E':
  936.         { 
  937.             int i = XVECLEN ( body, p - fmt );
  938.             
  939.             while ( i -- )
  940.             {
  941.             kstores_mark_touched ( XVECEXP ( body, p - fmt, i ));
  942.             }
  943.         }
  944.         }
  945.         ++ p;
  946.     }
  947.     }
  948. }
  949.  
  950. static void
  951. kloads_mark_touched ( body )
  952.     rtx body;
  953. {
  954.     if (( SET == GET_CODE ( body )) ||
  955.     ( CLOBBER == GET_CODE ( body )) ||
  956.     ( PRE_INC == GET_CODE ( body )) ||
  957.     ( PRE_DEC == GET_CODE ( body )) ||
  958.     ( POST_INC == GET_CODE ( body )) ||
  959.     ( POST_DEC == GET_CODE ( body )))
  960.     {
  961.     body = XEXP ( body, 0 );
  962.     
  963.     if ((( MEM == GET_CODE ( body )) &&
  964.          ( RTX_RELOAD_GENERATED_P ( XEXP ( body, 0 )))) ||
  965.         (( SUBREG == GET_CODE ( body )) &&
  966.          ( MEM == GET_CODE ( XEXP ( body, 0 ))) &&
  967.          ( RTX_RELOAD_GENERATED_P ( XEXP ( XEXP ( body, 0 ), 0 )))))
  968.     {
  969.         /* blow out any previous value overlapping this load
  970.            target. */
  971.         
  972.         int offset = get_offset ( body );
  973.         int i = trailing_affected_slots ( GET_MODE ( body ));
  974.         
  975.         kill_prior_contents ( slot_value, offset );
  976.         
  977.         slot_value[ offset ] = rtx_alloc ( UNKNOWN );
  978.         slot_value_mode[ offset ] = GET_MODE ( body );
  979.         
  980.         while ( i )
  981.         {
  982.         slot_value[ ( i -- ) + offset ] = look_to_previous_elem;
  983.         }
  984.         kloads_mark_touched ( XEXP ( body, 0 ));
  985.         
  986.         return;
  987.     }
  988.     
  989.     else if ( REG == GET_CODE ( body ))
  990.     {
  991.         /* waste any register values overlapping with the target
  992.            of this INSN. */
  993.  
  994.         int regno = REGNO ( body );
  995.         int i = HARD_REGNO_NREGS ( regno, GET_MODE ( body ));
  996.         
  997.         kill_prior_contents ( reg_value, regno );
  998.         
  999.         reg_value[ regno ] = rtx_alloc ( UNKNOWN );
  1000.         reg_value_mode[ regno ] = GET_MODE ( body );
  1001.         
  1002.         while ( -- i )
  1003.         {
  1004.         reg_value[ i + regno ] = look_to_previous_elem;
  1005.         }
  1006.     }
  1007.     }
  1008.     else
  1009.     { 
  1010.     char *fmt = GET_RTX_FORMAT ( GET_CODE ( body ));
  1011.     char c, *p = fmt;
  1012.     
  1013.     
  1014.     while ( '\0' != ( c = *p ))
  1015.     {
  1016.         switch ( c )
  1017.         {
  1018.         case 'e':
  1019.         kloads_mark_touched ( XEXP ( body, p - fmt ));
  1020.         break;
  1021.         
  1022.         case 'E':
  1023.         { 
  1024.             int i = XVECLEN ( body, p - fmt );
  1025.             
  1026.             while ( i -- )
  1027.             {
  1028.             kloads_mark_touched ( XVECEXP ( body, p - fmt, i ));
  1029.             }
  1030.         }
  1031.         }
  1032.         ++ p;
  1033.     }
  1034.     }
  1035. }
  1036. /* note the uses of stack slots within the RTL expression passed as an 
  1037.    argument. here, I'm being conservative in that I'm not checking whether
  1038.    or not a reference to a reload generated stack slot is a use, or a def:
  1039.    I'm counting all references as uses. I don't think we'll ever see a
  1040.    reload address inside a complex expression such as PARALLEL, but the
  1041.    extra code protects against deleting needed defs just in case. */
  1042.  
  1043. static void
  1044. compliv_mark_touched ( body )
  1045.     rtx body;
  1046. {
  1047.     if (( SET == GET_CODE ( body )) ||
  1048.     ( CLOBBER == GET_CODE ( body )) ||
  1049.     ( PRE_INC == GET_CODE ( body )) ||
  1050.     ( PRE_DEC == GET_CODE ( body )) ||
  1051.     ( POST_INC == GET_CODE ( body )) ||
  1052.     ( POST_DEC == GET_CODE ( body )))
  1053.     {
  1054.     body = XEXP ( body, 0 );
  1055.     
  1056.     if ((( MEM == GET_CODE ( body )) &&
  1057.          ( RTX_RELOAD_GENERATED_P ( XEXP ( body, 0 )))) ||
  1058.         (( SUBREG == GET_CODE ( body )) &&
  1059.          ( MEM == GET_CODE ( XEXP ( body, 0 ))) &&
  1060.          ( RTX_RELOAD_GENERATED_P ( XEXP ( XEXP ( body, 0 ), 0 )))))
  1061.     {
  1062.         /* blow out any previous value overlapping this load
  1063.            target. */
  1064.         
  1065.         int offset = get_offset ( body );
  1066.         int i = trailing_affected_slots ( GET_MODE ( body ));
  1067.         
  1068.         kill_prior_contents ( slot_value, offset );
  1069.         
  1070.         slot_value[ offset ] = NULL;
  1071.         slot_value_mode[ offset ] = VOIDmode;
  1072.         
  1073.         while ( i )
  1074.         {
  1075.         slot_value[ ( i -- ) + offset ] = NULL;
  1076.         }
  1077.         compliv_mark_touched ( XEXP ( body, 0 ));
  1078.         
  1079.         return;
  1080.     }
  1081.     }
  1082.     else
  1083.     { 
  1084.     char *fmt = GET_RTX_FORMAT ( GET_CODE ( body ));
  1085.     char c, *p = fmt;
  1086.     
  1087.     
  1088.     while ( '\0' != ( c = *p ))
  1089.     {
  1090.         switch ( c )
  1091.         {
  1092.         case 'e':
  1093.         compliv_mark_touched ( XEXP ( body, p - fmt ));
  1094.         break;
  1095.         
  1096.         case 'E':
  1097.         { 
  1098.             int i = XVECLEN ( body, p - fmt );
  1099.             
  1100.             while ( i -- )
  1101.             {
  1102.             compliv_mark_touched ( XVECEXP ( body, p - fmt, i ));
  1103.             }
  1104.         }
  1105.         }
  1106.         ++ p;
  1107.     }
  1108.     }
  1109. }
  1110.  
  1111. /* this function takes an array of rtx values that represent either adjacent
  1112.    memory locations or registers. it mark as invalid any data value that 
  1113.    encompasses the element specified by the index. e.g. if we do a SImode load
  1114.    into a DImode stack slot, then we must kill ALL of the DImode value. We
  1115.    could be less conservative with constant values, maybe we'd want to add that
  1116.    later (yeah-right). */
  1117.  
  1118. static void
  1119. kill_prior_contents ( rtx_array, index )
  1120.     rtx *rtx_array;
  1121.     int index;
  1122. {
  1123.     while ( look_to_previous_elem == rtx_array[ index ] )
  1124.     {
  1125.     rtx_array[ index -- ] = NULL;
  1126.     }
  1127.     rtx_array[ index ] = NULL;
  1128. }
  1129.  
  1130. /* this function traverses a basic block and tries to eliminate some spills
  1131.    that are needlessly created by poor lifetime management. we often see
  1132.    the following code sequence:
  1133.  
  1134.    (1) ( SET ( MEMx ) ( R1 ))
  1135.    ...
  1136.    (2) ( SET ( R1 ) ( any value ))
  1137.    ...
  1138.    (3) ( SET ( R2 ) ( MEMx ))
  1139.  
  1140.    we want to reorder this as (1) (3) (2). This will allow kill_stores to 
  1141.    possibly elininate (1), and allow kill_loads to transform (3) into a 
  1142.    register copy. The only dflow requirement is that R2 cannot be live between
  1143.    (2) and (3) in the original insn ordering. It is easier for us 
  1144.    (computationally) to instead ensure that R2 is not live between (1) and (3).
  1145.    This could cause us to miss a potential opportunity, but in the code
  1146.    I've examined (durbin.c), it wouldn't */
  1147.  
  1148. /* we do this in one traversal of the basic block, making an extra subpass
  1149.    for each optimization opportunity. */
  1150.  
  1151. static void
  1152. compress_lives ( block_num )
  1153.     int block_num;
  1154. {
  1155.     extern int get_frame_size ( );
  1156.     
  1157.     /* the maximum stack slot offset in this function. */
  1158.     int max_slot_offset = get_frame_size ( ) + 1
  1159.  
  1160. #ifdef FRAME_GROWS_DOWNWARD
  1161.     - STARTING_FRAME_OFFSET;
  1162. #else
  1163.     + STARTING_FRAME_OFFSET;
  1164. #endif
  1165.  
  1166.     /* scan through the basic block once, in execution order. */
  1167.     rtx insn = basic_block_head[ block_num ];
  1168.     rtx tail = basic_block_end[ block_num ];
  1169.     
  1170.     /* allocate memory for the grouping marker. */
  1171.     look_to_previous_elem = (rtx) alloca ( sizeof ( struct rtx_def ));
  1172.  
  1173.     /* we keep an array of last sets, an entry for each stack slot. the
  1174.        insn rtx of the last insn to SET the slot is kept in the array. 
  1175.        NULL implies ambiguity. look_to_previous_elem indicates a mult-slot
  1176.        SET. */
  1177.     slot_value = (rtx*) alloca ( sizeof ( rtx ) * max_slot_offset );
  1178.     
  1179.     /* we keep an array of modes corresponding to the above insn array. */
  1180.     slot_value_mode = (enum machine_mode*)
  1181.     alloca ( sizeof ( enum machine_mode ) * max_slot_offset );
  1182.     
  1183.     /* initialize the data-structures. */
  1184.     { 
  1185.     int i = max_slot_offset;
  1186.     
  1187.     while ( i -- )
  1188.     {
  1189.         slot_value[i] = NULL;
  1190.         slot_value_mode[i] = VOIDmode;
  1191.     }
  1192.     }
  1193.     
  1194.     /* algorithm (loosely speaking): 
  1195.        traverse the block in execution order. if the current insn is a 
  1196.        store to a memory stack slot, then we set the slot_value element 
  1197.        corrsponding to the slot to point to the current insn. the 
  1198.        slot_value_mode
  1199.        array element is given the mode used access the stack slot.
  1200.        if the current insn is a load from a stack slot, see if we can 
  1201.        compress a lifetime. otherwise, note any stack slot references by
  1202.        setting the corresponding slot_value array element to NULL. 
  1203.  
  1204.        to compress a lifetime, check whether R2 is referenced within the
  1205.        interval bounded by the current insn and the insn specified by
  1206.        the corresponding element of the slot_value array. if not, copy the 
  1207.        PATTERN of the current insn into a new insn following the insn
  1208.        specified by the slot_value array (whew!). delete the current insn.
  1209.        kill_loads, (and possibly kill_stores) will make the code more
  1210.        efficient. */
  1211.  
  1212.     while ( insn != tail )
  1213.     {
  1214.     rtx body;
  1215.     
  1216.     if ( INSN != GET_CODE ( insn ))
  1217.     {
  1218.         insn = NEXT_INSN ( insn );
  1219.         
  1220.         continue;
  1221.     }
  1222.     body = PATTERN ( insn );
  1223.     
  1224.     /* do we have a store to a stack slot ? */
  1225.  
  1226.     if (( SET == GET_CODE ( body )) &&
  1227.         ( REG == GET_CODE ( SET_SRC ( body ))) &&
  1228.         ( MEM == GET_CODE ( SET_DEST ( body ))) &&
  1229.         ( RTX_RELOAD_GENERATED_P ( XEXP ( SET_DEST ( body ), 0 ))))
  1230.     {
  1231.         int offset = get_offset ( SET_DEST ( body ));
  1232.  
  1233.         kill_prior_contents ( slot_value, offset );
  1234.             
  1235.         slot_value[ offset ] = insn;
  1236.         slot_value_mode[ offset ] = GET_MODE ( SET_SRC ( body ));
  1237.  
  1238.         /* handle the case where the the mode uses more than one memory
  1239.            location. */
  1240.         {
  1241.         int i = trailing_affected_slots ( slot_value_mode[ offset ] );
  1242.             
  1243.         while ( i )
  1244.         {
  1245.             slot_value[ ( i -- ) + offset ] = look_to_previous_elem;
  1246.         }
  1247.         }
  1248.     }
  1249.  
  1250.     /* do we have a load from a stack slot ? */
  1251.  
  1252.     else if (( SET == GET_CODE ( body )) &&
  1253.          ( REG == GET_CODE ( SET_DEST ( body ))) &&
  1254.          ( MEM == GET_CODE ( SET_SRC ( body ))) &&
  1255.          ( RTX_RELOAD_GENERATED_P ( XEXP ( SET_SRC ( body ), 0 ))))
  1256.     {
  1257.         int offset = get_offset ( SET_SRC ( body ));
  1258.         enum machine_mode mode = GET_MODE ( SET_SRC ( body ));
  1259.         
  1260.         if (( NULL != slot_value[ offset ] ) &&
  1261.         ( look_to_previous_elem != slot_value[ offset ] ) &&
  1262.         ( mode == slot_value_mode[ offset ] ) &&
  1263.         ( ! reg_possibly_live_between_p ( SET_DEST ( body ),
  1264.                          slot_value[ offset ], insn )))
  1265.         {
  1266.         /* shorten the lifetime of a spilled register. */
  1267.         
  1268.         /* move the load to immediately after the store. */
  1269.  
  1270.         emit_insn_after ( copy_rtx ( PATTERN ( insn )), 
  1271.                  slot_value[ offset ] );
  1272.         
  1273.         /* eliminate the second load. */
  1274.  
  1275.         PUT_CODE ( insn, NOTE );
  1276.         NOTE_LINE_NUMBER ( insn ) = NOTE_INSN_DELETED;
  1277.         NOTE_SOURCE_FILE ( insn ) = 0;
  1278.         }
  1279.     }
  1280.     
  1281.     /* note any stack slots that are clobbered by the current insn. */
  1282.  
  1283.     else
  1284.     {
  1285.         compliv_mark_touched ( PATTERN ( insn ));
  1286.     }
  1287.     
  1288.     /* move on to the next insn */
  1289.  
  1290.     insn = NEXT_INSN ( insn );
  1291.     }
  1292. #if defined( USE_C_ALLOCA )
  1293.     (void) alloca ( 0 );
  1294. #endif
  1295. }
  1296.  
  1297. /* we go through the function body once and find all of the stores to 
  1298.    unused reload stack slots. we keep an array of void*, with an element
  1299.    corresponding to each reload stack offset location. initially, all
  1300.    elements are set to NULL. if a slot is ever loaded from, its element
  1301.    is changed to & is_used_p. if a slot is stored to, and its element is
  1302.    is still NULL, a list is created and placed in the element. the list 
  1303.    will contain all of the insns that store to this slot. 
  1304.    after we've passed through the function, we go back through the array
  1305.    and delete all of the insns in each list. these isns are the stores into
  1306.    unused stack slots. */
  1307.    
  1308. struct store_note
  1309. {
  1310.     rtx which_insn;
  1311.     struct store_note *link;
  1312. };
  1313.  
  1314. static void
  1315. global_kill_stores ( insns )
  1316.     rtx insns;
  1317. {
  1318.     extern int get_frame_size ( );
  1319.     
  1320.     rtx look = insns;
  1321.     
  1322.     struct store_note *free_list = NULL;
  1323.     
  1324.     /* the maximum stack slot offset in this function. */
  1325.     int i, subreg = 0, is_used_p, max_slot_offset = get_frame_size ( ) + 1
  1326.     
  1327. #ifdef FRAME_GROWS_DOWNWARD
  1328.     - STARTING_FRAME_OFFSET;
  1329. #else
  1330.         + STARTING_FRAME_OFFSET;
  1331. #endif
  1332.  
  1333.     /* the array used to track unused stack slots. */
  1334.     void **usage_array = (void**) 
  1335.     xmalloc ( sizeof ( void* ) * max_slot_offset );
  1336.     
  1337.     /* initialize record keeper array */
  1338.     for ( i = 0; i < max_slot_offset; ++ i )
  1339.     {
  1340.     usage_array[i] = NULL;
  1341.     }
  1342.  
  1343.     /* look through the function. */
  1344.     while ( NULL != look )
  1345.     {
  1346.     /* is this possibly a read from a reload stack slot ? */
  1347.     if ((( subreg = 0 ), ( INSN == GET_CODE ( look ))) &&
  1348.         SET == GET_CODE ( PATTERN ( look )) &&
  1349.         ( MEM == GET_CODE ( SET_SRC ( PATTERN ( look ))) ||
  1350.          ( subreg = ( SUBREG == GET_CODE ( SET_SRC ( PATTERN ( look ))) &&
  1351.              MEM == GET_CODE ( XEXP ( SET_SRC ( PATTERN ( look ))
  1352.                          , 0 ))))) &&
  1353.         RTX_RELOAD_GENERATED_P 
  1354.         (( subreg ) ? XEXP ( XEXP ( SET_SRC ( PATTERN ( look )), 0 ), 0 ) :
  1355.          XEXP ( SET_SRC ( PATTERN ( look )), 0 )))
  1356.     {
  1357.         int slot_num = get_offset ( SET_SRC ( PATTERN ( look )));
  1358.         int trailing_slots = trailing_affected_slots 
  1359.         ( GET_MODE (( subreg ) ? 
  1360.                 XEXP ( SET_SRC ( PATTERN ( look )), 0 )
  1361.                 : SET_SRC ( PATTERN ( look ))));
  1362.         do
  1363.         {
  1364.         /* deallocate any previously built chain. */
  1365.         if ( NULL != usage_array[ slot_num ] &&
  1366.             ( & is_used_p ) != usage_array[ slot_num ] )
  1367.         {
  1368.             struct store_note *dead, *next = usage_array[ slot_num ];
  1369.             
  1370.             do
  1371.             {
  1372.             dead = next;
  1373.             next = next->link;
  1374.             dead->link = free_list;
  1375.             free_list = dead;
  1376.             }
  1377.             while ( NULL != next );
  1378.         }
  1379.         usage_array[ slot_num ++ ] = (void*) & is_used_p;
  1380.         }
  1381.         while ( trailing_slots -- );
  1382.     }
  1383.  
  1384.  
  1385.     /* otherwise is this possibly a write to a reload stack slot ? */
  1386.     else if ((( subreg = 0 ), ( INSN == GET_CODE ( look ))) &&
  1387.          SET == GET_CODE ( PATTERN ( look )) &&
  1388.          ( MEM == GET_CODE ( SET_DEST ( PATTERN ( look ))) ||
  1389.           ( subreg = 
  1390.            ( SUBREG == GET_CODE ( SET_DEST ( PATTERN ( look ))) &&
  1391.             MEM == GET_CODE ( XEXP ( SET_DEST ( PATTERN ( look ))
  1392.                         , 0 ))))) &&
  1393.          RTX_RELOAD_GENERATED_P 
  1394.          (( subreg ) ? 
  1395.           XEXP ( XEXP ( SET_DEST ( PATTERN ( look )), 0 ), 0 ) :
  1396.           XEXP ( SET_DEST ( PATTERN ( look )), 0 )))
  1397.     {
  1398.         int dont_bother = 0;
  1399.         int i, slot_num = get_offset ( SET_DEST ( PATTERN ( look )));
  1400.         int j, trailing_slots = trailing_affected_slots 
  1401.         ( GET_MODE (( subreg ) ?
  1402.                 XEXP ( SET_DEST ( PATTERN ( look )), 0 ) :
  1403.                 SET_DEST ( PATTERN ( look ))));
  1404.         
  1405.         i = slot_num, j = trailing_slots;
  1406.         do
  1407.         {
  1408.         dont_bother |= ( ((void*) & is_used_p ) 
  1409.                 == usage_array[ i ++ ] );
  1410.         }
  1411.         while ( j -- );
  1412.         
  1413.         /* note the store if we should. */
  1414.  
  1415.         if ( ! dont_bother )
  1416.         {
  1417.         struct store_note *new;
  1418.  
  1419.         if ( NULL == free_list )
  1420.         {
  1421.             new = (struct store_note*) xmalloc
  1422.             ( sizeof ( struct store_note ));
  1423.         }
  1424.         else
  1425.         {
  1426.             new = free_list;
  1427.             free_list = free_list->link;
  1428.         }
  1429.         new->which_insn = look;
  1430.         new->link = (struct store_note*) usage_array[ slot_num ];
  1431.         usage_array[ slot_num ] = (void*) new;
  1432.         }
  1433.     }
  1434.  
  1435.     /* move on to the next insn */
  1436.     look = NEXT_INSN( look );
  1437.     }
  1438.  
  1439.     /* now, blow out the worthless stores. */
  1440.     for ( i = 0; i < max_slot_offset; ++ i )
  1441.     {
  1442.     if ( NULL != usage_array[i] && 
  1443.         ((void*) & is_used_p ) != usage_array[i] )
  1444.     {
  1445.         struct store_note *dead;
  1446.         struct store_note *next = (struct store_note*) usage_array[i];
  1447.         
  1448.         do
  1449.         {
  1450.         dead = next;
  1451.         PUT_CODE ( dead->which_insn, NOTE );
  1452.         NOTE_LINE_NUMBER ( dead->which_insn ) = NOTE_INSN_DELETED;
  1453.         NOTE_SOURCE_FILE ( dead->which_insn ) = 0;
  1454.         next = dead->link;
  1455.         free ( dead );
  1456.         }
  1457.         while ( NULL != next );
  1458.     }
  1459.     }
  1460.     /* deallocate the whole array. */
  1461.     free ( usage_array );
  1462.  
  1463.     while ( NULL != free_list )
  1464.     {
  1465.     struct store_note *dead = free_list;
  1466.     free_list = free_list->link;
  1467.     free ( dead );
  1468.     }
  1469. }
  1470.  
  1471. /* return 1 if the register(s) referenced by the REG rtx hard_reg might
  1472.    be referenced by any of the insns between first and last. return 0 
  1473.    otherwise. */
  1474.  
  1475. static int
  1476. reg_possibly_live_between_p ( hard_reg, first, last )
  1477.     rtx hard_reg, first, last;
  1478. {
  1479.     
  1480.     if ( first == last )
  1481.     {
  1482.     return 0;
  1483.     }
  1484.     first = NEXT_INSN ( first );
  1485.     
  1486.     while ( first != last )
  1487.     {
  1488.     if (( INSN == GET_CODE ( first )) || 
  1489.         ( JUMP_INSN == GET_CODE ( first )))
  1490.     {
  1491.         if ( reg_possibly_live ( hard_reg, PATTERN ( first )))
  1492.         {
  1493.         return 1;
  1494.         }
  1495.     }
  1496.     else if ( CALL_INSN == GET_CODE ( first ))
  1497.     {
  1498.         /* look for the usual usage */
  1499.         if ( reg_possibly_live ( hard_reg, PATTERN ( first )))
  1500.         {
  1501.         return 1;
  1502.         }
  1503.         
  1504.         /* check for CALL_USED/CLOBBERED_REGS */
  1505.         { 
  1506.         int i = REGNO ( hard_reg );
  1507.         int trailers = HARD_REGNO_NREGS ( i, GET_MODE ( hard_reg ));
  1508.         
  1509.         do 
  1510.         {
  1511.             if (( TEST_HARD_REG_BIT ( call_used_reg_set, i )) ||
  1512.             ( TEST_HARD_REG_BIT ( fixed_reg_set, i ++ )))
  1513.             {
  1514.             return 1;
  1515.             }
  1516.         }
  1517.         while ( trailers -- );
  1518.         }
  1519.     }
  1520.     first = NEXT_INSN ( first );
  1521.     }
  1522.     return 0;
  1523. }
  1524.  
  1525. static int
  1526. reg_possibly_live ( reg, pat )
  1527.     rtx reg, pat;
  1528. {
  1529.     if ( REG == GET_CODE ( pat ))
  1530.     {
  1531.     int r1 = REGNO ( reg ), r2 = REGNO ( pat );
  1532.     int l1 = HARD_REGNO_NREGS ( r1, GET_MODE ( reg )) - 1;
  1533.     int l2 = HARD_REGNO_NREGS ( r2, GET_MODE ( pat )) - 1;
  1534.     
  1535.     
  1536.     if ((( r1 <= r2 ) && (( r1 + l1 ) >= r2 )) ||
  1537.         (( r2 <= r1 ) && (( r2 + l2 ) >= r1 )))
  1538.     {
  1539.         return 1;
  1540.     }
  1541.     return 0;
  1542.     }
  1543.     else
  1544.     {
  1545.     char *fmt = GET_RTX_FORMAT ( GET_CODE ( pat ));
  1546.     char c, *p = fmt;
  1547.  
  1548.     while ( '\0' != ( c = *p ))
  1549.     {
  1550.         switch ( c )
  1551.         {
  1552.         case 'e':
  1553.         if ( reg_possibly_live ( reg, XEXP ( pat, p - fmt )))
  1554.         {
  1555.             return 1;
  1556.         }
  1557.         break;
  1558.         
  1559.         case 'E':
  1560.         { 
  1561.             int i = XVECLEN ( pat, p - fmt );
  1562.  
  1563.             while ( i -- )
  1564.             {
  1565.             if ( reg_possibly_live ( reg, 
  1566.                         XVECEXP ( pat, p - fmt, i )))
  1567.             {
  1568.                 return 1;
  1569.             }
  1570.             }
  1571.         }
  1572.         break;
  1573.         }
  1574.         ++ p;
  1575.     }
  1576.     return 0;
  1577.     }
  1578. }
  1579.  
  1580. /* like reg_set_p, as provided by GNU, but only looks for mods that are
  1581.    the object of a set. */
  1582. static int
  1583. addr_reg_set_p ( reg, pat )
  1584.     rtx reg, pat;
  1585. {
  1586.     if ( SET == GET_CODE ( pat ))
  1587.     {
  1588.     enum machine_mode mode;
  1589.     
  1590.     pat = XEXP ( pat, 0 );
  1591.     mode = GET_MODE ( pat );
  1592.     
  1593.     while ( SUBREG == GET_CODE ( pat ))
  1594.     {
  1595.         pat = XEXP ( pat, 0 );
  1596.     }
  1597.     
  1598.     if ( REG == GET_CODE ( pat ))
  1599.     {
  1600.         int p_regno = REGNO ( pat );
  1601.         int p_len = HARD_REGNO_NREGS ( p_regno, GET_MODE ( pat ));
  1602.         int regno = REGNO ( reg );
  1603.         int len = HARD_REGNO_NREGS ( regno, GET_MODE ( reg ));
  1604.  
  1605.         if ((( p_regno <= regno ) && (( p_regno + p_len ) >= regno )) ||
  1606.         (( regno <= p_regno ) && (( regno + len ) >= p_regno )))
  1607.         {
  1608.         return 1;
  1609.         }
  1610.     }
  1611.     }
  1612.  
  1613.     { 
  1614.     char *fmt = GET_RTX_FORMAT ( GET_CODE ( pat ));
  1615.     char c, *p = fmt;
  1616.     
  1617.     
  1618.     while ( '\0' != ( c = *p ))
  1619.     {
  1620.         switch ( c )
  1621.         {
  1622.         case 'e':
  1623.         if ( addr_reg_set_p ( reg, XEXP ( pat, p - fmt )))
  1624.         {
  1625.             return 1;
  1626.         }
  1627.         break;
  1628.         
  1629.         case 'E':
  1630.         { 
  1631.             int i = XVECLEN ( pat, p - fmt );
  1632.             
  1633.             while ( i -- )
  1634.             {
  1635.             if ( addr_reg_set_p ( reg, 
  1636.                          XVECEXP ( pat, p - fmt, i )))
  1637.             {
  1638.                 return 1;
  1639.             }
  1640.             }
  1641.         }
  1642.         }
  1643.         ++ p;
  1644.     }
  1645.     }
  1646.     return 0;
  1647. }
  1648.  
  1649. /* this vairable is set by function_logue to tell sdbout.c which pro/ep
  1650.    sequence is being used. */
  1651. int logue_index;
  1652.  
  1653. void 
  1654. function_logue ( file, size, epilogue_p )
  1655.     FILE *file;
  1656.     int size, epilogue_p;
  1657. {
  1658.     static mem_space_fixed = 0;
  1659.     
  1660.     char *tst = ( current_func_info & FUNC_RETURNS_FLOAT ) ?
  1661. #if defined( DSP96000 )
  1662.     "ftst    d0" : "tst    d0";
  1663. #else
  1664.     "tst    a" : "tst    a";
  1665. #endif
  1666.     
  1667.     static struct
  1668.     {
  1669.     char *pro, *epi;
  1670.     }
  1671.     *chosen, stack_check_logues = 
  1672.     /* a special epilog/prolog that watches for stack heap collision. */
  1673.     {    "\
  1674.     move    r0,@:(r6)+\n\
  1675.     move    ssh,@:(r6)+\n\
  1676.     move    #%d,n6\n\
  1677.     move    r6,r0\n\
  1678.     move    (r6)+n6\n\
  1679.     jsr    F__stack_check\n",
  1680.       "\
  1681.     move    (r0)-\n\
  1682.     move    @:(r0)-,ssh\n\
  1683.     move    r0,r6\n\
  1684.     %s    @:(r0),r0\n\
  1685.     rts\n\n" },
  1686.  
  1687.     logues[] = 
  1688.     {
  1689.     /* 00000: non-void, no stack parms, leaf, no frame temps. */
  1690.     { "", 
  1691.       "\
  1692.     %s\n\
  1693.     rts\n\n" },
  1694.  
  1695.     /* 00001: non-void, stack parms, leaf, no frame temps. */
  1696. #if defined( DSP96000 )
  1697.     { "\
  1698.     move    r0,@:(r6)+\n\
  1699.     lea    (r6)+,r0\n",
  1700.       "\
  1701.     %s    @:-(r6),r0\n\
  1702.     rts\n\n" },
  1703. #else
  1704.     { "\
  1705.     move    r0,@:(r6)+\n\
  1706.     lua    (r6)+,r0\n",
  1707.       "\
  1708.     %s    @:-(r6),r0\n\
  1709.     rts\n\n" },
  1710. #endif
  1711.  
  1712.     /* 00010: non-void, no stack parms, not leaf, no frame temps. */
  1713.     { "\
  1714.     move    ssh,@:(r6)+\n",
  1715.       "\
  1716.     %s    (r6)-\n\
  1717.     move    @:(r6),ssh\n\
  1718.     rts\n\n" },
  1719.     
  1720.     /* 00011: non-void, stack parms, not leaf, no frame temps. */
  1721.     { "\
  1722.     move    r0,@:(r6)+\n\
  1723.     move    ssh,@:(r6)+\n\
  1724.     move    r6,r0\n",
  1725.       "\
  1726.     move    (r6)-\n\
  1727.     move    @:(r6)-,ssh\n\
  1728.     %s    @:(r6),r0\n\
  1729.     rts\n\n" },
  1730.  
  1731.     /* 00100: non-void, no stack parms, leaf, 1 frame tmp. */
  1732.     { "\
  1733.     move    r0,@:(r6)+\n\
  1734.     move    r6,r0\n\
  1735.     move    (r6)+\n",
  1736.       "\
  1737.     move    (r0)-\n\
  1738.     move    r0,r6\n\
  1739.     %s    @:(r0),r0\n\
  1740.     rts\n\n" },
  1741.  
  1742.     /* 00101: non-void, stack parms, leaf, 1 frame tmp. */
  1743. #if defined( DSP96000 )
  1744.     { "\
  1745.     move    r0,@:(r6)+\n\
  1746.     move    (r6)+\n\
  1747.     move    r6,r0\n\
  1748.     move    (r6)+\n",
  1749.       "\
  1750.     lea    (r6+-3),r6\n\
  1751.     %s    @:(r6),r0\n\
  1752.     rts\n\n" },
  1753. #else
  1754.     { "\
  1755.     move    r0,@:(r6)+\n\
  1756.     move    (r6)+\n\
  1757.     move    r6,r0\n\
  1758.     move    (r6)+\n",
  1759.       "\
  1760.     move    (r6)-\n\
  1761.     move    (r6)-\n\
  1762.     move    (r6)-\n\
  1763.     %s    @:(r6),r0\n\
  1764.     rts\n\n" },
  1765. #endif
  1766.  
  1767.     /* 00110: non-void, no stack parms, not leaf, 1 frame tmp. */
  1768.     { "\
  1769.     move    r0,@:(r6)+\n\
  1770.     move    ssh,@:(r6)+\n\
  1771.     move    r6,r0\n\
  1772.     move    (r6)+\n",
  1773.       "\
  1774.     move    (r0)-\n\
  1775.     move    @:(r0)-,ssh\n\
  1776.     move    r0,r6\n\
  1777.     %s    @:(r0),r0\n\
  1778.     rts\n\n" },
  1779.  
  1780.     /* 00111: non-void, stack parms, not leaf, 1 frame tmp. */
  1781.     { "\
  1782.     move    r0,@:(r6)+\n\
  1783.     move    ssh,@:(r6)+\n\
  1784.     move    r6,r0\n\
  1785.     move    (r6)+\n",
  1786.       "\
  1787.     move    (r0)-\n\
  1788.     move    @:(r0)-,ssh\n\
  1789.     move    r0,r6\n\
  1790.     %s    @:(r0),r0\n\
  1791.     rts\n\n" },
  1792.  
  1793.     /* 01000 thru 01011: illegal. */
  1794.         { "", "" },
  1795.         { "", "" },
  1796.         { "", "" },
  1797.         { "", "" },
  1798.  
  1799.     /* 01100: non-void, no stack parms, leaf, n frame tmps. */
  1800.     { "\
  1801.     move    r0,@:(r6)+\n\
  1802.     move    #%d,n6\n\
  1803.     move    r6,r0\n\
  1804.     move    (r6)+n6\n",
  1805.       "\
  1806.     move    (r0)-\n\
  1807.     move    r0,r6\n\
  1808.     %s    @:(r0),r0\n\
  1809.     rts\n\n" },
  1810.  
  1811.     /* 01101: non-void, stack parms, leaf, n frame tmps. */
  1812.     { "\
  1813.     move    r0,@:(r6)+\n\
  1814.     move    (r6)+\n\
  1815.     move    #%d,n6\n\
  1816.     move    r6,r0\n\
  1817.     move    (r6)+n6\n",
  1818.       "\
  1819.     move    (r0)-\n\
  1820.     move    (r0)-\n\
  1821.     move    r0,r6\n\
  1822.     %s    @:(r0),r0\n\
  1823.     rts\n\n" },
  1824.  
  1825.     /* 01110: non-void, no stack parms, not leaf, n frame tmps. */
  1826.     { "\
  1827.     move    r0,@:(r6)+\n\
  1828.     move    ssh,@:(r6)+\n\
  1829.     move    #%d,n6\n\
  1830.     move    r6,r0\n\
  1831.     move    (r6)+n6\n",
  1832.       "\
  1833.     move    (r0)-\n\
  1834.     move    @:(r0)-,ssh\n\
  1835.     move    r0,r6\n\
  1836.     %s    @:(r0),r0\n\
  1837.     rts\n\n" },
  1838.  
  1839.         /* 01111: non-void, stack parms, not leaf, n frame tmps. */
  1840.     { "\
  1841.     move    r0,@:(r6)+\n\
  1842.     move    ssh,@:(r6)+\n\
  1843.     move    #%d,n6\n\
  1844.     move    r6,r0\n\
  1845.     move    (r6)+n6\n",
  1846.       "\
  1847.     move    (r0)-\n\
  1848.     move    @:(r0)-,ssh\n\
  1849.     move    r0,r6\n\
  1850.     %s    @:(r0),r0\n\
  1851.     rts\n\n" },
  1852.  
  1853.     /* 10000: void, no stack parms, leaf, no frame temps. */
  1854.     { "", 
  1855.       "\
  1856.     rts\n\n" },
  1857.  
  1858.     /* 10001: void, stack parms, leaf, no frame temps. */
  1859. #if defined( DSP96000 )
  1860.     { "\
  1861.     move    r0,@:(r6)+\n\
  1862.     lea    (r6)+,r0\n",
  1863.       "\
  1864.     move    @:-(r6),r0\n\
  1865.     rts\n\n" },
  1866. #else
  1867.     { "\
  1868.     move    r0,@:(r6)+\n\
  1869.     lua    (r6)+,r0\n",
  1870.       "\
  1871.     move    @:-(r6),r0\n\
  1872.     rts\n\n" },
  1873. #endif
  1874.  
  1875.     /* 10010: void, no stack parms, not leaf, no frame temps. */
  1876.     { "\
  1877.     move    ssh,@:(r6)+\n",
  1878.       "\
  1879.     move    @:-(r6),ssh\n\
  1880.     rts\n\n" },
  1881.     
  1882.     /* 10011: void, stack parms, not leaf, no frame temps. */
  1883.     { "\
  1884.     move    r0,@:(r6)+\n\
  1885.     move    ssh,@:(r6)+\n\
  1886.     move    r6,r0\n",
  1887.       "\
  1888.     move    (r6)-\n\
  1889.     move    @:(r6)-,ssh\n\
  1890.     move    @:(r6),r0\n\
  1891.     rts\n\n" },
  1892.  
  1893.     /* 10100: void, no stack parms, leaf, 1 frame tmp. */
  1894.     { "\
  1895.     move    r0,@:(r6)+\n\
  1896.     move    r6,r0\n\
  1897.     move    (r6)+\n",
  1898.       "\
  1899.     move    (r0)-\n\
  1900.     move    r0,r6\n\
  1901.     move    @:(r0),r0\n\
  1902.     rts\n\n" },
  1903.  
  1904.     /* 10101: void, stack parms, leaf, 1 frame tmp. */
  1905. #if defined( DSP96000 )
  1906.     { "\
  1907.     move    r0,@:(r6)+\n\
  1908.     move    (r6)+\n\
  1909.     move    r6,r0\n\
  1910.     move    (r6)+\n",
  1911.       "\
  1912.     lea    (r6+-3),r6\n\
  1913.     move    @:(r6),r0\n\
  1914.     rts\n\n" },
  1915. #else
  1916.     { "\
  1917.     move    r0,@:(r6)+\n\
  1918.     move    (r6)+\n\
  1919.     move    r6,r0\n\
  1920.     move    (r6)+\n",
  1921.       "\
  1922.     move    (r6)-\n\
  1923.     move    (r6)-\n\
  1924.     move    (r6)-\n\
  1925.     move    @:(r6),r0\n\
  1926.     rts\n\n" },
  1927. #endif
  1928.  
  1929.     /* 10110: void, no stack parms, not leaf, 1 frame tmp. */
  1930.     { "\
  1931.     move    r0,@:(r6)+\n\
  1932.     move    ssh,@:(r6)+\n\
  1933.     move    r6,r0\n\
  1934.     move    (r6)+\n",
  1935.       "\
  1936.     move    (r0)-\n\
  1937.     move    @:(r0)-,ssh\n\
  1938.     move    r0,r6\n\
  1939.     move    @:(r0),r0\n\
  1940.     rts\n\n" },
  1941.  
  1942.     /* 10111: void, stack parms, not leaf, 1 frame tmp. */
  1943.     { "\
  1944.     move    r0,@:(r6)+\n\
  1945.     move    ssh,@:(r6)+\n\
  1946.     move    r6,r0\n\
  1947.     move    (r6)+\n",
  1948.       "\
  1949.     move    (r0)-\n\
  1950.     move    @:(r0)-,ssh\n\
  1951.     move    r0,r6\n\
  1952.     move    @:(r0),r0\n\
  1953.     rts\n\n" },
  1954.  
  1955.     /* 11000 thru 11011: illegal. */
  1956.         { "", "" },
  1957.         { "", "" },
  1958.         { "", "" },
  1959.         { "", "" },
  1960.  
  1961.     /* 11100: void, no stack parms, leaf, n frame tmps. */
  1962.     { "\
  1963.     move    r0,@:(r6)+\n\
  1964.     move    #%d,n6\n\
  1965.     move    r6,r0\n\
  1966.     move    (r6)+n6\n",
  1967.       "\
  1968.     move    (r0)-\n\
  1969.     move    r0,r6\n\
  1970.     move    @:(r0),r0\n\
  1971.     rts\n\n" },
  1972.  
  1973.     /* 11101: void, stack parms, leaf, n frame tmps. */
  1974.     { "\
  1975.     move    r0,@:(r6)+\n\
  1976.     move    (r6)+\n\
  1977.     move    #%d,n6\n\
  1978.     move    r6,r0\n\
  1979.     move    (r6)+n6\n",
  1980.       "\
  1981.     move    (r0)-\n\
  1982.     move    (r0)-\n\
  1983.     move    r0,r6\n\
  1984.     move    @:(r0),r0\n\
  1985.     rts\n\n" },
  1986.  
  1987.     /* 11110: void, no stack parms, not leaf, n frame tmps. */
  1988.     { "\
  1989.     move    r0,@:(r6)+\n\
  1990.     move    ssh,@:(r6)+\n\
  1991.     move    #%d,n6\n\
  1992.     move    r6,r0\n\
  1993.     move    (r6)+n6\n",
  1994.       "\
  1995.     move    (r0)-\n\
  1996.     move    @:(r0)-,ssh\n\
  1997.     move    r0,r6\n\
  1998.     move    @:(r0),r0\n\
  1999.     rts\n\n" },
  2000.  
  2001.         /* 11111: void, stack parms, not leaf, n frame tmps. */
  2002.     { "\
  2003.     move    r0,@:(r6)+\n\
  2004.     move    ssh,@:(r6)+\n\
  2005.     move    #%d,n6\n\
  2006.     move    r6,r0\n\
  2007.     move    (r6)+n6\n",
  2008.       "\
  2009.     move    (r0)-\n\
  2010.     move    @:(r0)-,ssh\n\
  2011.     move    r0,r6\n\
  2012.     move    @:(r0),r0\n\
  2013.     rts\n\n" },
  2014.  
  2015.     /* terminator. */    
  2016.         { NULL, NULL }
  2017.     };
  2018.     
  2019.     if ( ! mem_space_fixed )
  2020.     {
  2021.     int i;
  2022.     struct dsp_string temp;
  2023.     
  2024.     for ( i = 0; NULL != logues[ i ].pro; ++ i )
  2025.     {
  2026.         temp.init = 0;
  2027.         strcpy ( temp.string, logues[ i ].pro );
  2028.         fix_mem_space ( & temp );
  2029.         logues[i].pro = (char*) malloc ( strlen ( temp.string ) + 1 );
  2030.         strcpy ( logues[i].pro, temp.string );
  2031.  
  2032.         temp.init = 0;
  2033.         strcpy ( temp.string, logues[ i ].epi );
  2034.         fix_mem_space ( & temp );
  2035.         logues[i].epi = (char*) malloc ( strlen ( temp.string ) + 1 );
  2036.         strcpy ( logues[i].epi, temp.string );
  2037.     }
  2038.     temp.init = 0;
  2039.     strcpy ( temp.string, stack_check_logues.pro );
  2040.     fix_mem_space ( & temp );
  2041.     stack_check_logues.pro = (char*) malloc ( strlen ( temp.string ) + 1 );
  2042.     strcpy ( stack_check_logues.pro, temp.string );
  2043.     
  2044.     temp.init = 0;
  2045.     strcpy ( temp.string, stack_check_logues.epi );
  2046.     fix_mem_space ( & temp );
  2047.     stack_check_logues.epi = (char*) malloc ( strlen ( temp.string ) + 1 );
  2048.     strcpy ( stack_check_logues.epi, temp.string );
  2049.  
  2050.     mem_space_fixed = 1;
  2051.     }
  2052.     
  2053.     /* switch bits are set if (0th bit is LSBit):
  2054.        0: the function has stack parameters.
  2055.        1: the function is not a leaf function (has call(s)).
  2056.        3,2: the function has no frame based temps (00), the function
  2057.             has one frame based temp (01), or the function has more than
  2058.         one frame based temp (11).
  2059.        4: the function is of type void.
  2060.     */
  2061.  
  2062.     if ( TARGET_STACK_CHECK )
  2063.     {
  2064.     chosen = & stack_check_logues;
  2065.     logue_index = -1;
  2066.     }
  2067.     else if ( TARGET_CALL_OVERHEAD_REDUCTION )
  2068.     {
  2069.     logue_index = (( 0 != ( current_func_info & FUNC_HAS_STACK_PARMS )) |
  2070.                (( 0 != ( current_func_info & FUNC_ISNT_LEAF )) << 1 ) |
  2071.                (( 0 != size ) << 2 ) |
  2072.                (( 1 < size ) << 3 ) |
  2073.                (( 0 != ( current_func_info & FUNC_RETURNS_VOID ))
  2074.             << 4 ));
  2075.     
  2076.     chosen = & logues[ logue_index ];
  2077.     }
  2078.     else
  2079.     {
  2080.     /* if they've turned off call overhead reduction, go for the safest
  2081.        possible pro/epilogue: stack parms, non-leaf, > 1 frame temps, and
  2082.        not a void function. */
  2083.  
  2084.     chosen = & logues[ logue_index = 0x0f ];
  2085.     }
  2086.     
  2087.     /* if we have a % we need to emit a test instruction, or specify size */
  2088.     if ( epilogue_p )
  2089.     {
  2090.     PopRegs ( file );
  2091.     
  2092.     if ( strchr ( chosen->epi, '%' ))
  2093.     {
  2094.         fprintf ( file, chosen->epi, tst );
  2095.     }
  2096.     else
  2097.     {
  2098.         fprintf ( file, chosen->epi );
  2099.     }
  2100.     }
  2101.     else
  2102.     {
  2103. #if defined( DSP56000 )
  2104.     /* on the 56k, we need to clear out the assumed n register values
  2105.        at the beginning of the function. */
  2106.     clear_n_reg_values ( );
  2107. #endif
  2108.     if ( strchr ( chosen->pro, '%' ))
  2109.     {
  2110.         fprintf ( file, chosen->pro, size );
  2111.     }
  2112.     else
  2113.     {
  2114.         fprintf ( file, chosen->pro );
  2115.     }
  2116.  
  2117. #if defined( DSP96000 )
  2118.     SetLocalBusy ( );
  2119. #endif
  2120.     PushRegs ( file );
  2121.     }
  2122. }
  2123.  
  2124. /*
  2125.  * Print out the section header and assembler defines / options at the
  2126.  * start of file.
  2127.  */
  2128.  
  2129. void
  2130. asm_file_start ( file )
  2131.     FILE* file;
  2132. {
  2133.     char *section, *replace;
  2134.  
  2135. #if defined( SDB_DEBUGGING_INFO )
  2136.     if ( write_symbols == SDB_DEBUG )
  2137.     {
  2138.     sdbout_filename ( file, main_input_filename );
  2139.     }
  2140. #endif
  2141.  
  2142.     section = strcpy ( malloc ( strlen ( main_input_filename ) + 1 ),
  2143.               main_input_filename );
  2144.     
  2145.     while ( replace = strpbrk ( section, ".-" ))
  2146.     {
  2147.     *replace = '_';
  2148.     }
  2149.     
  2150.     /* use last part of path only */
  2151.     if (( NULL != ( replace = strrchr ( section, '/' ))) ||
  2152.     ( NULL != ( replace = strrchr ( section, '\\' ))))
  2153.     {
  2154.     section = replace + 1;
  2155.     }
  2156.     
  2157.     fprintf ( file, "\tsection\t%s\n", section );
  2158.     fprintf ( file, "\topt so,nomd\n\tpage 132,66,3,3\n" );
  2159. }
  2160.  
  2161.  
  2162. void
  2163. asm_file_end ( file )
  2164.     FILE* file;
  2165. {
  2166.     fprintf ( file, "\n\tendsec\n" );
  2167. }
  2168.  
  2169. void 
  2170. output_ascii ( file, P, size )
  2171.     FILE* file;
  2172.     char* P;
  2173.     int size;
  2174. {
  2175.     int i;
  2176.     
  2177.     for ( i = 0; i < size; i++ )
  2178.     {
  2179.     if ( 0 == ( i % 15 ) )
  2180.     {
  2181.         fprintf ( file, "\n\tdc\t" );
  2182.     }
  2183.     else
  2184.     {
  2185.         putc ( ',', file );
  2186.     }
  2187.  
  2188.     if (( 0x40 < *P && 0x5b > *P ) || ( 0x60 < *P && 0x7b > *P ) ||
  2189.         ( 0x2f < *P && 0x3a > *P ))
  2190.     {
  2191.         putc ( '\'', file );
  2192.         fputc ( *P++, file );
  2193.         putc ( '\'', file );
  2194.     }
  2195.     else
  2196.     {
  2197.         fprintf ( file, "$%02X", *P++ );
  2198.     }
  2199.     }
  2200.     putc ( '\n', file );
  2201. }
  2202.  
  2203. /*
  2204.  * For local lables to be useful within inline assembly calls, A unique
  2205.  * global lable must be emmited before and after the each such invocation.
  2206.  */
  2207. char* 
  2208. asm_app_toggle ()
  2209. {
  2210.     static int LabelNo = 0;
  2211.     static char Label[20];
  2212.     sprintf ( Label, "ASM_APP_%X\n", LabelNo++ );
  2213.     return ( Label );
  2214. }
  2215.  
  2216. int 
  2217. increment_operand ( Op, Mode )
  2218.     rtx Op;
  2219.     enum machine_mode Mode;
  2220. {
  2221.     return ( CONST_INT == GET_CODE ( Op )
  2222.         && ( 2 == INTVAL ( Op )
  2223.         || 1 == INTVAL ( Op )
  2224.         || -1 == INTVAL ( Op )
  2225.         || -2 == INTVAL ( Op ) ) );
  2226. }
  2227.  
  2228. char*
  2229. fix_mem_space ( template_string )
  2230.     struct dsp_string* template_string;
  2231. {
  2232.     char* p;
  2233.     
  2234.     if ( 0 != template_string->init )
  2235.     {
  2236.     return & ( template_string->string[0] );
  2237.     }
  2238.     
  2239.     for ( p = & ( template_string->string[0] ); '\0' != *p; ++ p )
  2240.     {
  2241.     if ( '@' == *p )
  2242.     {
  2243.         *p = mem_space;
  2244.     }
  2245.     }
  2246.     template_string->init = 1;
  2247.  
  2248.     return & ( template_string->string[0] );
  2249. }
  2250.  
  2251. /* The following is an ad-hoc scheme for making sure we don't generate
  2252.  * do loops with pipline conflicts. Note that there is an insn for the "do",
  2253.  * and another for the "od" (end-o-do). The latter never actually causes 
  2254.  * an instruction in the assembly language output; it is used to indicate
  2255.  * the implicit back-branch at the do target label to the optimizer.
  2256.  *
  2257.  * 1) When we emit a do insn, peek forward to the next insn. If this insn
  2258.  *    uses an address register, mark the corresponding bit in the stack of
  2259.  *    register use bit masks, and increment the stack pointer.
  2260.  *
  2261.  * 2) When we emit an od insn, peek backward to the previous insn. if it
  2262.  *    "move"s to an address register, check the corresponding bit in the bit
  2263.  *    mask at the top of the stack. if it is set, we have a conflict. Emit
  2264.  *    a nop to avert the pipeline hazard. In either case, decrement the
  2265.  *    bit mask stack pointer before reading from the stack.
  2266.  *
  2267.  * NOTE: we use unsigned char to contain the bit mask because we have 
  2268.  *       only eight address registers on either chip.
  2269.  */
  2270.  
  2271. unsigned int do_loop_nest_level = 0;
  2272. unsigned char bit_mask_stack[ MAX_DO_LOOP_NESTING ];
  2273.  
  2274. void
  2275. record_address_regs_used ( insn )
  2276.     rtx insn;
  2277. {
  2278.     unsigned char mask = 0, flag = 1;
  2279.     rtx reg, pattern;
  2280.     
  2281.     /* if there's no real chance of conflict... */
  2282.     if ( const0_rtx == insn )
  2283.     {
  2284.     bit_mask_stack[ do_loop_nest_level ++ ] = 0;
  2285.     
  2286.     return;
  2287.     }
  2288.     pattern = PATTERN ( insn );
  2289.     
  2290. #if defined( DSP56000 )
  2291.     reg = gen_rtx ( REG, Pmode, 6 );
  2292. #elif defined( DSP96000 )
  2293.     reg = gen_rtx ( REG, Pmode, 24 );
  2294. #endif
  2295.     
  2296.     for ( ; 0xff & flag; flag <<= 1, ++ REGNO ( reg ))
  2297.     {
  2298.     if ( reg_mentioned_p ( reg, pattern ))
  2299.     {
  2300.         mask |= flag;
  2301.     }
  2302.     }
  2303.     bit_mask_stack[ do_loop_nest_level ++ ] = mask;
  2304. }
  2305.  
  2306. #ifdef INSN_MACHINE_INFO
  2307. const INSN_MACHINE_INFO insn_machine_info[];
  2308. #endif
  2309.  
  2310. int
  2311. conflicting_address_regs_set_p ( insn )
  2312.     rtx insn;
  2313. {
  2314.     rtx reg, pattern;
  2315.     unsigned char mask = bit_mask_stack[ -- do_loop_nest_level ];
  2316.  
  2317.     if ( const0_rtx == insn ||
  2318.     insn_machine_info[ INSN_CODE ( insn )].no_latency_addr_reg_op_p )
  2319.     {
  2320.     return 0;
  2321.     }
  2322.     pattern = PATTERN ( insn );
  2323.     
  2324. #if defined( DSP56000 )
  2325.     reg = gen_rtx ( REG, Pmode, 6 );
  2326. #elif defined( DSP96000 )
  2327.     reg = gen_rtx ( REG, Pmode, 24 );
  2328. #endif
  2329.     
  2330.     for ( ; 0xff & mask; mask >>= 1, ++ REGNO ( reg ))
  2331.     {
  2332.     if (( 1 & mask ) && ( addr_reg_set_p ( reg, pattern )))
  2333.     {
  2334.         return 1;
  2335.     }
  2336.     }
  2337.     return 0;
  2338. }
  2339.  
  2340. int
  2341. target_mbtowc ( pwc, s, n )
  2342.     int *pwc;
  2343.     char *s;
  2344.     int n;
  2345. {
  2346.     if ( NULL == s )
  2347.     {
  2348.     return 0;
  2349.     }
  2350.  
  2351.     if ( 0 == n )
  2352.     {
  2353.     return -1;
  2354.     }
  2355.  
  2356.     {
  2357.         char skinny = *( s ++ );
  2358.     
  2359.     if ( '\0' == skinny )
  2360.     {
  2361.         if ( NULL != pwc )
  2362.         {
  2363.         *pwc = 0;
  2364.         }
  2365.         return 0;
  2366.     }
  2367.     
  2368.     { 
  2369.         int skinnys_left;
  2370.         int wide = 0;
  2371.         
  2372.         n = ( n < (CHAR_TYPE_SIZE/8)) ? n : (CHAR_TYPE_SIZE/8);
  2373.         
  2374.         skinnys_left = n;
  2375.         
  2376.         if ( NULL == pwc )
  2377.         {
  2378.         do
  2379.         {
  2380.             skinny = *( s ++ );
  2381.         }
  2382.         while (( -- skinnys_left ) && ( '\0' != skinny ));
  2383.         }
  2384.         else
  2385.         {
  2386.         do
  2387.         {
  2388.             wide = ( wide << 8 ) | skinny;
  2389.             skinny = *( s ++ );
  2390.         }
  2391.         while (( -- skinnys_left ) && ( '\0' != skinny ));
  2392.  
  2393.         *pwc = wide;
  2394.         }
  2395.         return (int) ( n - skinnys_left );
  2396.     }
  2397.     }
  2398. }
  2399.  
  2400. int
  2401. target_mbstowcs ( pwcs, s )
  2402.     int *pwcs;
  2403.     char *s;
  2404. {
  2405.     int converted;
  2406.     int i;
  2407.     
  2408.     for ( i = 0; ; i ++ )
  2409.     {
  2410.     /* check for invalid character */
  2411.     if ( ( converted = target_mbtowc( pwcs, s, CHAR_TYPE_SIZE/8 ) ) == -1 )
  2412.     {
  2413.         return ( (int) -1 );
  2414.     }
  2415.     
  2416.     /* check for NULL termination character */
  2417.     if ( converted == 0 )
  2418.     {
  2419.         break;
  2420.     }
  2421.     
  2422.     /* bump pwcs and s */
  2423.     pwcs ++ ;
  2424.     s += converted;
  2425.     }
  2426.     
  2427.     return i;
  2428. }
  2429.  
  2430. /* this global variable is used to cut down on the number of stupid org
  2431.    statements. when we see a counter pragma we set it, when we org we clear
  2432.    it. */
  2433. int counter_pragma_seen = 0;
  2434.  
  2435. /* process allowed pragmas. warn about unrecognized pragmas. */
  2436. int
  2437. dsp_process_pragma_line ( f )
  2438.     FILE *f;
  2439. {
  2440.     /* read up to EOF or \n to get the pragma line. */
  2441.     char pragma_text[ 128 ];
  2442.     
  2443.     int retval, last = 0, bytes_left = sizeof ( pragma_text ) - 1;
  2444.     
  2445.     while ( bytes_left -- )
  2446.     {
  2447.     retval = getc ( f );
  2448.     pragma_text[ last ] = retval;
  2449.     
  2450.     if ( EOF == retval || '\n' == retval )
  2451.     {
  2452.         pragma_text[ last ] = '\0';
  2453.         break;
  2454.     }
  2455.     ++ last;
  2456.     }
  2457.     
  2458.     /* we got the string, now use strtok to get the parts. right now we
  2459.        use brute force to parse, maybe if we add a bunch of pragmas, we
  2460.        should use some CS technique. */
  2461.  
  2462.     { 
  2463.     char **mod_spot, *default_val, *counter, *new_value;
  2464. #if ! defined( MIPSEL ) && ( defined( sun ) && defined( __GNUC__ ) )
  2465.     char delim[] = " \n\t\v\b\r";
  2466. #else
  2467.     char delim[7];
  2468.     strcpy( delim, " \n\t\v\b\r" );
  2469. #endif
  2470.     
  2471.     /* get the counter */
  2472.     counter = strtok ( pragma_text, delim );
  2473.     
  2474.     if ( NULL == counter )
  2475.     {
  2476.         goto fail;
  2477.     }
  2478.     
  2479.     if ( 0 == strcmp ( "y_run", counter )) 
  2480.     {
  2481.         mod_spot = & y_run;
  2482.         default_val = y_run_default;
  2483.     }
  2484.     else if ( 0 == strcmp ( "y_load", counter )) 
  2485.     {
  2486.         mod_spot = & y_load;
  2487.         default_val = y_load_default;
  2488.     }
  2489.     else if ( 0 == strcmp ( "x_run", counter )) 
  2490.     {
  2491.         mod_spot = & x_run;
  2492.         default_val = x_run_default;
  2493.     }
  2494.     else if ( 0 == strcmp ( "x_load", counter )) 
  2495.     {
  2496.         mod_spot = & x_load;
  2497.         default_val = x_load_default;
  2498.     }
  2499.     else if ( 0 == strcmp ( "l_run", counter )) 
  2500.     {
  2501.         mod_spot = & l_run;
  2502.         default_val = l_run_default;
  2503.     }
  2504.     else if ( 0 == strcmp ( "l_load", counter )) 
  2505.     {
  2506.         mod_spot = & l_load;
  2507.         default_val = l_load_default;
  2508.     }
  2509.     else if ( 0 == strcmp ( "p_run", counter )) 
  2510.     {
  2511.         mod_spot = & p_run;
  2512.         default_val = p_run_default;
  2513.     }
  2514.     else if ( 0 == strcmp ( "p_load", counter )) 
  2515.     {
  2516.         mod_spot = & p_load;
  2517.         default_val = p_load_default;
  2518.     }
  2519.     else
  2520.     {
  2521.         goto fail;
  2522.     }
  2523.     
  2524.     /* get the new value for orgs */
  2525.     new_value = strtok ( NULL, delim );
  2526.  
  2527.     if ( NULL == new_value )
  2528.     {
  2529.         /* switch back to the default_val. */
  2530.         if ( safe_strcmp ( *mod_spot, default_val ))
  2531.         {
  2532.         counter_pragma_seen = 1;
  2533.         }
  2534.         *mod_spot = default_val;
  2535.     }
  2536.     else
  2537.     {
  2538.         /* put the new counter into effect. */
  2539.         if ( safe_strcmp ( *mod_spot, new_value ))
  2540.         {
  2541.         counter_pragma_seen = 1;
  2542.         }
  2543.         *mod_spot = strcpy
  2544.         ((char*) xmalloc ( strlen ( new_value ) + 1 ), new_value );
  2545.     }
  2546.     }
  2547.     return retval;
  2548.     
  2549.  fail:
  2550.     warning ( "invalid #pragma string has been ignored" );
  2551.     
  2552.     return retval;
  2553. }
  2554.  
  2555. /* all org asm statements are sprintf'ed into this array */
  2556. static char org_text[ 512 ];
  2557.  
  2558. /* create the proper org statement for data. */
  2559. char *
  2560. text_section_asm_op ( )
  2561. {
  2562.     /* org statements are assumed to be of the form blah:blech. the blech is
  2563.        optional. if we switch back and forth betweem program and data, we 
  2564.        don't want to org multiple sections of code at blech, but we still want
  2565.        to use the counter blah. we waste everything after the colon after
  2566.        the full string is printed once. */
  2567.     char *colon;
  2568.     
  2569.     if ( NULL == p_load )
  2570.     {
  2571.     sprintf ( org_text, "\torg\t%s", p_run );
  2572.     }
  2573.     else
  2574.     {
  2575.     sprintf ( org_text, "\torg\t%s,%s", p_run, p_load );
  2576.     if ( p_load_default != p_load )
  2577.     {
  2578.         colon = strchr ( p_load, ':' );
  2579.         if ( NULL != colon )
  2580.         {
  2581.         * ( colon + 1 ) = '\0';
  2582.         }
  2583.     }
  2584.     }
  2585.     if ( p_run_default != p_run )
  2586.     {
  2587.     colon = strchr ( p_run, ':' );
  2588.     if ( NULL != colon )
  2589.     {
  2590.         * ( colon + 1 ) = '\0';
  2591.     }
  2592.     }
  2593.  
  2594.     return org_text;
  2595. }
  2596.  
  2597. /* create the proper org statement for data. */
  2598. char *
  2599. data_section_asm_op ( )
  2600. {
  2601.     /* org statements are assumed to be of the form blah:blech. the blech is
  2602.        optional. if we switch back and forth betweem program and data, we 
  2603.        don't want to org multiple sections of code at blech, but we still want
  2604.        to use the counter blah. we waste everything after the colon after
  2605.        the full string is printed once. */
  2606.     char *colon, *the_load, *the_run, *the_default_load, *the_default_run;
  2607.     
  2608.     switch ( memory_model )
  2609.     {
  2610.     case 'x':
  2611.     the_load = x_load;
  2612.     the_run = x_run;
  2613.     the_default_load = x_load_default;
  2614.     the_default_run = x_run_default;
  2615.     
  2616.     if ( NULL == x_load )
  2617.     {
  2618.         sprintf ( org_text, "\torg\t%s", x_run );
  2619.     }
  2620.     else
  2621.     {
  2622.         sprintf ( org_text, "\torg\t%s,%s", x_run, x_load );
  2623.     }
  2624.     break;
  2625.     
  2626.     case 'y':
  2627.     the_load = y_load;
  2628.     the_run = y_run;
  2629.     the_default_load = y_load_default;
  2630.     the_default_run = y_run_default;
  2631.  
  2632.     if ( NULL == y_load )
  2633.     {
  2634.         sprintf ( org_text, "\torg\t%s", y_run );
  2635.     }
  2636.     else
  2637.     {
  2638.         sprintf ( org_text, "\torg\t%s,%s", y_run, y_load );
  2639.     }
  2640.     break;
  2641.     
  2642.     case 'l':
  2643.     the_load = l_load;
  2644.     the_run = l_run;
  2645.     the_default_load = l_load_default;
  2646.     the_default_run = l_run_default;
  2647.  
  2648.     if ( NULL == l_load )
  2649.     {
  2650.         sprintf ( org_text, "\torg\t%s", l_run );
  2651.     }
  2652.     else
  2653.     {
  2654.         sprintf ( org_text, "\torg\t%s,%s", l_run, l_load );
  2655.     }
  2656.     break;
  2657.     
  2658.     default:
  2659.     abort ( );
  2660.     }
  2661.  
  2662.     if ( NULL != the_load && the_load != the_default_load )
  2663.     {
  2664.     colon = strchr ( the_load, ':' );
  2665.     if ( NULL != colon )
  2666.     {
  2667.         * ( colon + 1 ) = '\0';
  2668.     }
  2669.     }
  2670.     if ( the_run != the_default_run )
  2671.     {
  2672.     colon = strchr ( the_run, ':' );
  2673.     if ( NULL != colon )
  2674.     {
  2675.         * ( colon + 1 ) = '\0';
  2676.     }
  2677.     }
  2678.  
  2679.     return org_text;
  2680. }
  2681.  
  2682. static struct counter_bind
  2683. {
  2684.     char *x_run, *x_load, *y_run, *y_load, *l_run, *l_load, *p_run, *p_load;
  2685.     struct counter_bind *link;
  2686. }
  2687. *binding_stack = NULL;
  2688.  
  2689. /* save the current state of the run-time and load-time counters. change the
  2690.    counters to the values associated with the given declaration. */
  2691.  
  2692. void
  2693. push_counters ( decl )
  2694.     tree decl;
  2695. {
  2696.     char *new_x_run, *new_x_load;
  2697.     char *new_y_run, *new_y_load;
  2698.     char *new_l_run, *new_l_load;
  2699.     char *new_p_run, *new_p_load;
  2700.     
  2701.     struct counter_bind *new = (struct counter_bind*) 
  2702.     xmalloc ( sizeof ( struct counter_bind ));
  2703.     
  2704.     new->x_run = x_run, new->x_load = x_load;
  2705.     new->y_run = y_run, new->y_load = y_load;
  2706.     new->l_run = l_run, new->l_load = l_load;
  2707.     new->p_run = p_run, new->p_load = p_load;
  2708.  
  2709.     new->link = binding_stack;
  2710.     binding_stack = new;
  2711.     
  2712.     /* run time counters should never be NULL, load time counters sometimes
  2713.        are. */
  2714.     new_x_run = ( NULL == DECL_X_RUN ( decl )) ? x_run : DECL_X_RUN ( decl );
  2715.     new_x_load = DECL_X_LOAD ( decl );
  2716.     new_y_run = ( NULL == DECL_Y_RUN ( decl )) ? y_run : DECL_Y_RUN ( decl );
  2717.     new_y_load = DECL_Y_LOAD ( decl );
  2718.     new_l_run = ( NULL == DECL_L_RUN ( decl )) ? l_run : DECL_L_RUN ( decl );
  2719.     new_l_load = DECL_L_LOAD ( decl );
  2720.     new_p_run = ( NULL == DECL_P_RUN ( decl )) ? p_run : DECL_P_RUN ( decl );
  2721.     new_p_load = DECL_P_LOAD ( decl );
  2722.  
  2723.     if ( safe_strcmp ( new_x_run, x_run ) ||
  2724.     safe_strcmp ( new_y_run, y_run ) ||
  2725.     safe_strcmp ( new_l_run, l_run ) ||
  2726.     safe_strcmp ( new_p_run, p_run ) ||
  2727.     safe_strcmp ( new_x_load, x_load ) ||
  2728.     safe_strcmp ( new_y_load, y_load ) ||
  2729.     safe_strcmp ( new_l_load, l_load ) ||
  2730.     safe_strcmp ( new_p_load, p_load ))
  2731.     {
  2732.     counter_pragma_seen = 1;
  2733.  
  2734.     x_run = new_x_run;
  2735.     x_load = new_x_load;
  2736.     y_run = new_y_run;
  2737.     y_load = new_y_load;
  2738.     l_run = new_l_run;
  2739.     l_load = new_l_load;
  2740.     p_run = new_p_run;
  2741.     p_load = new_p_load;
  2742.     }
  2743. }
  2744.  
  2745. /* restore the counters to the state before push_counters was last called. */
  2746.  
  2747. void
  2748. pop_counters ( )
  2749. {
  2750.     struct counter_bind *dead = binding_stack;
  2751.     
  2752.     if ( safe_strcmp ( x_run, dead->x_run ) ||
  2753.     safe_strcmp ( x_load, dead->x_load ) ||
  2754.     safe_strcmp ( y_run, dead->y_run ) ||
  2755.     safe_strcmp ( y_load, dead->y_load ) ||
  2756.     safe_strcmp ( l_run, dead->l_run ) ||
  2757.     safe_strcmp ( l_load, dead->l_load ) ||
  2758.     safe_strcmp ( p_run, dead->p_run ) ||
  2759.     safe_strcmp ( p_load, dead->p_load ))
  2760.     {
  2761.     counter_pragma_seen = 1;
  2762.  
  2763.     x_run = dead->x_run, x_load = dead->x_load;
  2764.     y_run = dead->y_run, y_load = dead->y_load;
  2765.     l_run = dead->l_run, l_load = dead->l_load;
  2766.     p_run = dead->p_run, p_load = dead->p_load;
  2767.     }
  2768.     binding_stack = binding_stack->link;
  2769.     free ( dead );
  2770. }
  2771.  
  2772. static int
  2773. safe_strcmp ( s1, s2 )
  2774.     char *s1, *s2;
  2775. {
  2776.     if ( NULL == s1 )
  2777.     {
  2778.     if ( NULL == s2 )
  2779.     {
  2780.         return 0;
  2781.     }
  2782.     return 1;
  2783.     }
  2784.     if ( NULL == s2 )
  2785.     {
  2786.     return 1;
  2787.     }
  2788.     return strcmp ( s1, s2 );
  2789. }
  2790.